Decompiled source of Barter v0.1.4

plugins/Barter/Barter.Core.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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 ExtraPotions.Barter.Availability;
using ExtraPotions.Barter.Config;
using ExtraPotions.Barter.Lists;
using ExtraPotions.Barter.Trading;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: AssemblyInformationalVersion("0.1.4")]
[assembly: AssemblyProduct("Barter.Core")]
[assembly: AssemblyTitle("Barter.Core")]
[assembly: AssemblyVersion("0.1.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 ExtraPotions.Barter
{
	public static class BarterCore
	{
		public const string ProductId = "com.meadworks.barter";

		public const string LegacyProductId = "com.extrapotions.barter";

		public const string FilePrefix = "Barter.";

		public const string VanillaCurrency = "Coins";

		public const string CommonTrader = "common";

		public const int QualityStackMultiplier = 1000000;
	}
	public enum LegacyFileOutcome
	{
		None,
		Migrated,
		KeptNew,
		Failed
	}
	public sealed class LegacyFileResult
	{
		public LegacyFileOutcome Outcome { get; }

		public string? Backup { get; }

		public string? Problem { get; }

		internal LegacyFileResult(LegacyFileOutcome outcome, string? backup = null, string? problem = null)
		{
			Outcome = outcome;
			Backup = backup;
			Problem = problem;
		}
	}
	public static class LegacyFileMigration
	{
		public static LegacyFileResult PrepareSettings(string directory, string legacyName, string currentName)
		{
			LegacyFileResult legacyFileResult = Run(directory, legacyName, currentName);
			if (legacyFileResult.Outcome == LegacyFileOutcome.Failed)
			{
				throw new IOException("Legacy settings could not be carried over; initialization stopped before defaults were saved. " + legacyFileResult.Problem);
			}
			return legacyFileResult;
		}

		public static LegacyFileResult Run(string directory, string legacyName, string currentName)
		{
			if (string.IsNullOrEmpty(directory))
			{
				throw new ArgumentException("A config directory is required.", "directory");
			}
			if (string.IsNullOrEmpty(legacyName) || string.IsNullOrEmpty(currentName) || string.Equals(legacyName, currentName, StringComparison.OrdinalIgnoreCase))
			{
				throw new ArgumentException("Two different file names are required.");
			}
			string text = Path.Combine(directory, legacyName);
			string text2 = Path.Combine(directory, currentName);
			if (!File.Exists(text))
			{
				return new LegacyFileResult(LegacyFileOutcome.None);
			}
			if (File.Exists(text2))
			{
				return new LegacyFileResult(LegacyFileOutcome.KeptNew);
			}
			string text3 = text2 + ".migrate-" + Guid.NewGuid().ToString("N");
			try
			{
				byte[] array = File.ReadAllBytes(text);
				File.WriteAllBytes(text3, array);
				if (!((ReadOnlySpan<byte>)array).SequenceEqual((ReadOnlySpan<byte>)File.ReadAllBytes(text3)))
				{
					throw new IOException("The copied settings failed readback.");
				}
				if (File.Exists(text2))
				{
					return new LegacyFileResult(LegacyFileOutcome.KeptNew);
				}
				File.Move(text3, text2);
			}
			catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
			{
				return File.Exists(text2) ? new LegacyFileResult(LegacyFileOutcome.KeptNew) : new LegacyFileResult(LegacyFileOutcome.Failed, null, ex.Message);
			}
			finally
			{
				try
				{
					if (File.Exists(text3))
					{
						File.Delete(text3);
					}
				}
				catch (IOException)
				{
				}
				catch (UnauthorizedAccessException)
				{
				}
			}
			try
			{
				string text4 = FreeBackupName(text);
				File.Move(text, text4);
				return new LegacyFileResult(LegacyFileOutcome.Migrated, text4);
			}
			catch (Exception ex4) when (ex4 is IOException || ex4 is UnauthorizedAccessException)
			{
				return new LegacyFileResult(LegacyFileOutcome.Migrated, null, "The old file kept its name: " + ex4.Message);
			}
		}

		private static string FreeBackupName(string path)
		{
			string text = path + ".bak";
			if (!File.Exists(text))
			{
				return text;
			}
			for (int i = 1; i < 1000; i++)
			{
				string text2 = path + "." + i + ".bak";
				if (!File.Exists(text2))
				{
					return text2;
				}
			}
			throw new IOException("No free backup name for " + Path.GetFileName(path) + ".");
		}
	}
	public readonly struct PanelBox
	{
		public float X { get; }

		public float Y { get; }

		public float Width { get; }

		public float Height { get; }

		public float Right => X + Width;

		public float Top => Y + Height;

		public bool Usable
		{
			get
			{
				if (Finite(X) && Finite(Y) && Finite(Width) && Finite(Height) && Width > 0f)
				{
					return Height > 0f;
				}
				return false;
			}
		}

		public PanelBox(float x, float y, float width, float height)
		{
			X = x;
			Y = y;
			Width = width;
			Height = height;
		}

		public static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	public enum SidePanelSide
	{
		Left,
		Right,
		Below
	}
	public readonly struct SidePlace
	{
		public SidePanelSide Side { get; }

		public PanelBox Box { get; }

		public SidePlace(SidePanelSide side, PanelBox box)
		{
			Side = side;
			Box = box;
		}
	}
	public readonly struct OpenPlace
	{
		public bool HasSell { get; }

		public SidePlace Sell { get; }

		public bool HasPurse { get; }

		public SidePlace Purse { get; }

		public OpenPlace(bool hasSell, SidePlace sell, bool hasPurse, SidePlace purse)
		{
			HasSell = hasSell;
			Sell = sell;
			HasPurse = hasPurse;
			Purse = purse;
		}
	}
	public static class SidePanelFit
	{
		public static SidePlace Place(PanelBox canvas, PanelBox store, PanelBox? beside, float width, float height, float gap, float frame)
		{
			width = NonNegative(width);
			height = NonNegative(height);
			gap = NonNegative(gap);
			frame = NonNegative(frame);
			if (!canvas.Usable)
			{
				return new SidePlace(SidePanelSide.Left, new PanelBox(0f, 0f, width, height));
			}
			PanelBox other = (store.Usable ? store : canvas);
			PanelBox panelBox = NudgeY(canvas, Box(other.X - gap - width, other.Top - height, width, height), frame);
			if (Inside(canvas, panelBox, frame) && !Hits(panelBox, other) && !Hits(panelBox, beside))
			{
				return new SidePlace(SidePanelSide.Left, panelBox);
			}
			float num = other.Right;
			if (beside.HasValue)
			{
				PanelBox valueOrDefault = beside.GetValueOrDefault();
				if (valueOrDefault.Usable)
				{
					num = Math.Max(num, valueOrDefault.Right);
				}
			}
			PanelBox panelBox2 = NudgeY(canvas, Box(num + gap, other.Top - height, width, height), frame);
			if (Inside(canvas, panelBox2, frame) && !Hits(panelBox2, other) && !Hits(panelBox2, beside))
			{
				return new SidePlace(SidePanelSide.Right, panelBox2);
			}
			float num2 = other.Y;
			if (beside.HasValue)
			{
				PanelBox valueOrDefault2 = beside.GetValueOrDefault();
				if (valueOrDefault2.Usable)
				{
					num2 = Math.Min(num2, valueOrDefault2.Y);
				}
			}
			PanelBox panel = NudgeX(canvas, Box(other.X, num2 - gap - height, width, height), frame);
			return new SidePlace(SidePanelSide.Below, Clamp(canvas, panel, frame));
		}

		public static SidePlace PlaceSell(PanelBox canvas, PanelBox store, float width, float height, float gap, float frame)
		{
			width = NonNegative(width);
			height = NonNegative(height);
			gap = NonNegative(gap);
			frame = NonNegative(frame);
			if (!canvas.Usable)
			{
				return new SidePlace(SidePanelSide.Right, new PanelBox(0f, 0f, width, height));
			}
			PanelBox other = (store.Usable ? store : canvas);
			PanelBox panelBox = NudgeY(canvas, Box(other.Right + gap, other.Top - height, width, height), frame);
			if (Inside(canvas, panelBox, frame) && !Hits(panelBox, other))
			{
				return new SidePlace(SidePanelSide.Right, panelBox);
			}
			PanelBox panelBox2 = NudgeY(canvas, Box(other.X - gap - width, other.Top - height, width, height), frame);
			if (Inside(canvas, panelBox2, frame) && !Hits(panelBox2, other))
			{
				return new SidePlace(SidePanelSide.Left, panelBox2);
			}
			PanelBox panel = NudgeX(canvas, Box(other.X, other.Y - gap - height, width, height), frame);
			return new SidePlace(SidePanelSide.Below, Clamp(canvas, panel, frame));
		}

		public static OpenPlace PlaceBoth(PanelBox canvas, PanelBox store, bool sell, float sellWidth, float sellHeight, bool purse, float purseWidth, float purseHeight, float gap, float frame)
		{
			gap = NonNegative(gap);
			frame = NonNegative(frame);
			sell = sell && sellWidth > 0f && sellHeight > 0f && PanelBox.Finite(sellWidth) && PanelBox.Finite(sellHeight);
			purse = purse && purseWidth > 0f && purseHeight > 0f && PanelBox.Finite(purseWidth) && PanelBox.Finite(purseHeight);
			SidePlace sidePlace = default(SidePlace);
			bool flag = false;
			if (sell)
			{
				sidePlace = PlaceSell(canvas, store, sellWidth, sellHeight, gap, frame);
				flag = sidePlace.Side != SidePanelSide.Below;
			}
			SidePlace sidePlace2 = default(SidePlace);
			if (purse)
			{
				PanelBox? beside = ((sell && flag) ? new PanelBox?(sidePlace.Box) : ((PanelBox?)null));
				sidePlace2 = Place(canvas, store, beside, purseWidth, purseHeight, gap, frame);
			}
			if (sell && purse && Hits(sidePlace.Box, sidePlace2.Box))
			{
				if (flag)
				{
					sidePlace2 = Yield(canvas, store, sidePlace2, sidePlace.Box, gap, frame);
				}
				else
				{
					sidePlace = Yield(canvas, store, sidePlace, sidePlace2.Box, gap, frame);
				}
			}
			if (sell && purse && Hits(sidePlace.Box, sidePlace2.Box))
			{
				if (flag)
				{
					sidePlace = Yield(canvas, store, sidePlace, sidePlace2.Box, gap, frame);
				}
				else
				{
					sidePlace2 = Yield(canvas, store, sidePlace2, sidePlace.Box, gap, frame);
				}
			}
			return new OpenPlace(sell, sidePlace, purse, sidePlace2);
		}

		private static SidePlace Yield(PanelBox canvas, PanelBox store, SidePlace panel, PanelBox obstacle, float gap, float frame)
		{
			PanelBox panelBox = Separate(canvas, store, panel.Box, obstacle, gap, frame);
			if (!Hits(panelBox, obstacle))
			{
				return new SidePlace(panel.Side, panelBox);
			}
			return panel;
		}

		private static PanelBox Separate(PanelBox canvas, PanelBox store, PanelBox panel, PanelBox obstacle, float gap, float frame)
		{
			if (!Hits(panel, obstacle) || !canvas.Usable || !obstacle.Usable)
			{
				return panel;
			}
			bool found = false;
			PanelBox best = panel;
			float bestArea = 0f;
			float bestDist = 0f;
			Consider(obstacle.X - gap - panel.Width, panel.Y);
			Consider(obstacle.Right + gap, panel.Y);
			Consider(panel.X, obstacle.Top + gap);
			Consider(panel.X, obstacle.Y - gap - panel.Height);
			Consider(canvas.X + frame, canvas.Y + frame);
			Consider(canvas.Right - frame - panel.Width, canvas.Y + frame);
			Consider(canvas.X + frame, canvas.Top - frame - panel.Height);
			Consider(canvas.Right - frame - panel.Width, canvas.Top - frame - panel.Height);
			if (store.Usable)
			{
				Consider(store.X - gap - panel.Width, store.Top - panel.Height);
				Consider(store.Right + gap, store.Top - panel.Height);
			}
			if (!found)
			{
				return panel;
			}
			return best;
			void Consider(float x, float y)
			{
				PanelBox panelBox = Clamp(canvas, new PanelBox(x, y, panel.Width, panel.Height), frame);
				if (Inside(canvas, panelBox, frame) && !Hits(panelBox, obstacle))
				{
					float num = OverlapArea(panelBox, store);
					float num2 = panelBox.X - panel.X;
					float num3 = panelBox.Y - panel.Y;
					float num4 = num2 * num2 + num3 * num3;
					if (!found || num < bestArea - 0.5f || (Math.Abs(num - bestArea) <= 0.5f && num4 < bestDist))
					{
						found = true;
						best = panelBox;
						bestArea = num;
						bestDist = num4;
					}
				}
			}
		}

		private static float OverlapArea(PanelBox panel, PanelBox other)
		{
			if (!panel.Usable || !other.Usable)
			{
				return 0f;
			}
			float num = Math.Min(panel.Right, other.Right) - Math.Max(panel.X, other.X);
			float num2 = Math.Min(panel.Top, other.Top) - Math.Max(panel.Y, other.Y);
			if (num <= 0.5f || num2 <= 0.5f)
			{
				return 0f;
			}
			return num * num2;
		}

		private static PanelBox Box(float x, float y, float width, float height)
		{
			return new PanelBox(x, y, width, height);
		}

		private static float NonNegative(float value)
		{
			if (!PanelBox.Finite(value) || !(value > 0f))
			{
				return 0f;
			}
			return value;
		}

		private static PanelBox NudgeY(PanelBox canvas, PanelBox panel, float frame)
		{
			float num = canvas.Y + frame;
			float num2 = canvas.Top - frame;
			if (num2 - num < panel.Height)
			{
				return panel;
			}
			float num3 = panel.Y;
			if (num3 < num)
			{
				num3 = num;
			}
			if (num3 + panel.Height > num2)
			{
				num3 = num2 - panel.Height;
			}
			return new PanelBox(panel.X, num3, panel.Width, panel.Height);
		}

		private static PanelBox NudgeX(PanelBox canvas, PanelBox panel, float frame)
		{
			float num = canvas.X + frame;
			float num2 = canvas.Right - frame;
			if (num2 - num < panel.Width)
			{
				return panel;
			}
			float num3 = panel.X;
			if (num3 < num)
			{
				num3 = num;
			}
			if (num3 + panel.Width > num2)
			{
				num3 = num2 - panel.Width;
			}
			return new PanelBox(num3, panel.Y, panel.Width, panel.Height);
		}

		private static bool Inside(PanelBox canvas, PanelBox panel, float frame)
		{
			if (panel.X >= canvas.X + frame - 0.51f && panel.Y >= canvas.Y + frame - 0.51f && panel.Right <= canvas.Right - frame + 0.51f)
			{
				return panel.Top <= canvas.Top - frame + 0.51f;
			}
			return false;
		}

		private static bool Hits(PanelBox panel, PanelBox? other)
		{
			if (!other.HasValue || !other.Value.Usable)
			{
				return false;
			}
			PanelBox value = other.Value;
			float num = Math.Max(panel.X, value.X);
			float num2 = Math.Min(panel.Right, value.Right);
			float num3 = Math.Max(panel.Y, value.Y);
			float num4 = Math.Min(panel.Top, value.Top);
			if (num2 - num > 0.5f)
			{
				return num4 - num3 > 0.5f;
			}
			return false;
		}

		private static bool Hits(PanelBox panel, PanelBox other)
		{
			return Hits(panel, (PanelBox?)other);
		}

		private static PanelBox Clamp(PanelBox canvas, PanelBox panel, float frame)
		{
			float num = frame;
			float num2 = frame;
			if (canvas.Width <= panel.Width + frame * 2f)
			{
				num = 0f;
			}
			if (canvas.Height <= panel.Height + frame * 2f)
			{
				num2 = 0f;
			}
			float num3 = canvas.X + num;
			float num4 = canvas.Y + num2;
			float num5 = canvas.Right - num;
			float num6 = canvas.Top - num2;
			float x = panel.X;
			float y = panel.Y;
			x = ((!(num5 - num3 >= panel.Width)) ? num3 : Math.Max(num3, Math.Min(x, num5 - panel.Width)));
			y = ((!(num6 - num4 >= panel.Height)) ? (num6 - panel.Height) : Math.Max(num4, Math.Min(y, num6 - panel.Height)));
			return new PanelBox(x, y, panel.Width, panel.Height);
		}
	}
}
namespace ExtraPotions.Barter.Trading
{
	public interface IAuthorityStorage
	{
		bool Exists(string path);

		byte[] Read(string path, int maximumBytes);

		void WriteNew(string path, byte[] bytes);

		void Promote(string pending, string current, string backup);

		IEnumerable<string> Files(string directory, string pattern);

		void Delete(string path);
	}
	public sealed class AuthenticatedStateStore
	{
		private sealed class Record
		{
			internal string Object = "";

			internal string Field = "";

			internal string Value = "";
		}

		private sealed class LocalStorage : IAuthorityStorage
		{
			public bool Exists(string path)
			{
				return File.Exists(path);
			}

			public byte[] Read(string path, int maximumBytes)
			{
				using (RefillTiming.Measure(RefillTiming.Operation.LocalRead))
				{
					if (new FileInfo(path).Length > maximumBytes)
					{
						throw new InvalidDataException("Authority file bound");
					}
					byte[] array = File.ReadAllBytes(path);
					if (array.Length > maximumBytes)
					{
						throw new InvalidDataException("Authority file bound");
					}
					return array;
				}
			}

			public void WriteNew(string path, byte[] bytes)
			{
				using (RefillTiming.Measure(RefillTiming.Operation.LocalWrite))
				{
					Directory.CreateDirectory(Path.GetDirectoryName(path));
					using FileStream fileStream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None);
					fileStream.Write(bytes, 0, bytes.Length);
					using (RefillTiming.Measure(RefillTiming.Operation.Flush))
					{
						fileStream.Flush(flushToDisk: true);
					}
				}
			}

			public void Promote(string pending, string current, string backup)
			{
				using (RefillTiming.Measure(RefillTiming.Operation.Promote))
				{
					if (File.Exists(current))
					{
						File.Replace(pending, current, backup);
					}
					else
					{
						File.Move(pending, current);
					}
				}
			}

			public IEnumerable<string> Files(string directory, string pattern)
			{
				if (!Directory.Exists(directory))
				{
					return Array.Empty<string>();
				}
				return Directory.EnumerateFiles(directory, pattern);
			}

			public void Delete(string path)
			{
				File.Delete(path);
			}
		}

		public const int MaximumValueLength = 1048576;

		private const int MaximumRecordBytes = 4198400;

		private readonly string directory;

		private readonly IAuthorityStorage files;

		private readonly bool requireExistingKey;

		public AuthenticatedStateStore(string directory, IAuthorityStorage? storage = null, bool requireExistingKey = false)
		{
			this.directory = ((storage == null) ? Path.GetFullPath(directory) : directory);
			files = storage ?? new LocalStorage();
			this.requireExistingKey = requireExistingKey;
		}

		private string WorldDirectory(long world)
		{
			if (world == 0L)
			{
				throw new InvalidDataException("Authority world is unavailable");
			}
			return Path.Combine(directory, world.ToString(CultureInfo.InvariantCulture));
		}

		private static void Identity(string objectId, string field)
		{
			if (string.IsNullOrEmpty(objectId) || objectId.Length > 128 || string.IsNullOrEmpty(field) || field.Length > 256)
			{
				throw new InvalidDataException("Authority state identity bound");
			}
		}

		private string RecordPath(long world, string objectId, string field)
		{
			Identity(objectId, field);
			using SHA256 sHA = SHA256.Create();
			return Path.Combine(WorldDirectory(world), BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(objectId + "\0" + field))).Replace("-", "") + ".state");
		}

		private byte[] Key(long world, bool create)
		{
			string path = WorldDirectory(world);
			string text = Path.Combine(path, "authority.key");
			if (files.Exists(text + ".pending"))
			{
				byte[] array = null;
				string[] array2 = new string[2]
				{
					text,
					text + ".backup"
				};
				foreach (string path2 in array2)
				{
					if (!files.Exists(path2))
					{
						continue;
					}
					try
					{
						byte[] array3 = files.Read(path2, 32);
						if (array3.Length == 32)
						{
							array = array3;
							break;
						}
					}
					catch (InvalidDataException)
					{
					}
				}
				if (array != null)
				{
					byte[] array4 = null;
					try
					{
						array4 = files.Read(text + ".pending", 32);
					}
					catch (InvalidDataException)
					{
					}
					if (array4 == null || !((ReadOnlySpan<byte>)array4).SequenceEqual((ReadOnlySpan<byte>)array))
					{
						Quarantine(text + ".pending");
					}
				}
			}
			byte[] array5 = Recover(text, delegate(string p)
			{
				byte[] array6 = files.Read(p, 32);
				if (array6.Length != 32)
				{
					throw new InvalidDataException("Authority key bound");
				}
				return array6;
			});
			if (array5 != null)
			{
				return array5;
			}
			if (files.Files(path, "*.state*").Any())
			{
				throw new InvalidDataException("Authority key missing for existing state");
			}
			string path3 = Path.Combine(path, "allow-new-authority-key");
			bool flag = files.Exists(path3) && Encoding.UTF8.GetString(files.Read(path3, 64)).Trim() == world.ToString(CultureInfo.InvariantCulture);
			if (requireExistingKey && !flag)
			{
				throw new InvalidDataException("Existing world is missing Barter authority state. Restore Barter.Authority or create allow-new-authority-key containing the world UID to authorize its initial balance.");
			}
			if (!create)
			{
				return Array.Empty<byte>();
			}
			array5 = new byte[32];
			using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create())
			{
				randomNumberGenerator.GetBytes(array5);
			}
			AtomicWrite(text, array5);
			AtomicWrite(text + ".backup", array5);
			if (flag)
			{
				files.Delete(path3);
			}
			return array5;
		}

		private Record Decode(string path, long world, byte[] key, string? objectId = null, string? field = null)
		{
			byte[] array = files.Read(path, 4198400);
			if (array.Length < 48 || array.Length > 4198400)
			{
				throw new InvalidDataException("Authority record bound");
			}
			byte[] array2;
			using (HMACSHA256 hMACSHA = new HMACSHA256(key))
			{
				array2 = hMACSHA.ComputeHash(array, 32, array.Length - 32);
			}
			int num = 0;
			for (int i = 0; i < 32; i++)
			{
				num |= array2[i] ^ array[i];
			}
			if (num != 0)
			{
				throw new InvalidDataException("Authority state authentication failed");
			}
			using MemoryStream memoryStream = new MemoryStream(array, 32, array.Length - 32);
			using BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8);
			if (binaryReader.ReadInt32() != 1 || binaryReader.ReadInt64() != world)
			{
				throw new InvalidDataException("Authority world mismatch");
			}
			Record record = new Record
			{
				Object = binaryReader.ReadString(),
				Field = binaryReader.ReadString(),
				Value = binaryReader.ReadString()
			};
			Identity(record.Object, record.Field);
			if (objectId != null)
			{
				if (record.Object != objectId || record.Field != field)
				{
					throw new InvalidDataException("Authority state identity mismatch");
				}
			}
			else
			{
				string text = RecordPath(world, record.Object, record.Field).Replace('\\', '/');
				string text2 = path.Replace('\\', '/');
				if (text2 != text && text2 != text + ".pending" && text2 != text + ".backup")
				{
					throw new InvalidDataException("Authority record filename mismatch");
				}
			}
			if (record.Value.Length > 1048576 || memoryStream.Position != memoryStream.Length)
			{
				throw new InvalidDataException("Authority state value bound");
			}
			return record;
		}

		public string Read(long world, string objectId, string field)
		{
			return Read(world, objectId, field, RecordPath(world, objectId, field));
		}

		private string Read(long world, string objectId, string field, string path)
		{
			byte[] key = Key(world, create: false);
			return Recover(path, delegate(string p)
			{
				if (key.Length != 32)
				{
					throw new InvalidDataException("Authority key missing");
				}
				return Decode(p, world, key, objectId, field);
			})?.Value ?? "";
		}

		private T? Recover<T>(string path, Func<string, T> validate) where T : class
		{
			string text = path + ".pending";
			string text2 = path + ".backup";
			bool flag = false;
			if (files.Exists(text))
			{
				T val = null;
				try
				{
					val = validate(text);
				}
				catch (Exception ex) when (ex is InvalidDataException || ex is EndOfStreamException || ex is FormatException)
				{
					flag = true;
				}
				if (val != null)
				{
					files.Promote(text, path, text2);
					return val;
				}
				Quarantine(text);
			}
			if (files.Exists(path))
			{
				try
				{
					return validate(path);
				}
				catch (Exception ex2) when (ex2 is InvalidDataException || ex2 is EndOfStreamException || ex2 is FormatException)
				{
					flag = true;
				}
			}
			if (files.Exists(text2))
			{
				T result = validate(text2);
				byte[] bytes = files.Read(text2, 4198400);
				if (files.Exists(path))
				{
					Quarantine(path);
				}
				files.WriteNew(text, bytes);
				files.Promote(text, path, path + ".replaced");
				return result;
			}
			if (flag || files.Exists(path))
			{
				throw new InvalidDataException("No valid authority state remains; restore the world backup");
			}
			return null;
		}

		private void Quarantine(string path)
		{
			files.Promote(path, path + ".quarantine-" + Guid.NewGuid().ToString("N"), path + ".unused");
		}

		public void Write(long world, string objectId, string field, string value)
		{
			if (value == null || value.Length > 1048576)
			{
				throw new InvalidDataException("Authority state value bound");
			}
			string path = RecordPath(world, objectId, field);
			Read(world, objectId, field);
			byte[] key = Key(world, create: true);
			byte[] array;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8);
				binaryWriter.Write(1);
				binaryWriter.Write(world);
				binaryWriter.Write(objectId);
				binaryWriter.Write(field);
				binaryWriter.Write(value);
				array = memoryStream.ToArray();
			}
			using MemoryStream memoryStream2 = new MemoryStream();
			using (HMACSHA256 hMACSHA = new HMACSHA256(key))
			{
				byte[] array2 = hMACSHA.ComputeHash(array);
				memoryStream2.Write(array2, 0, array2.Length);
			}
			memoryStream2.Write(array, 0, array.Length);
			AtomicWrite(path, memoryStream2.ToArray());
		}

		public string[] Fields(long world, string objectId, string prefix)
		{
			Identity(objectId, string.IsNullOrEmpty(prefix) ? "*" : prefix);
			byte[] key = Key(world, create: false);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (string item in RecordFiles(WorldDirectory(world)))
			{
				Record record = Recover(item, (string p) => Decode(p, world, key));
				if (record != null && record.Object == objectId && record.Field.StartsWith(prefix ?? "", StringComparison.Ordinal))
				{
					Read(world, objectId, record.Field, item);
					hashSet.Add(record.Field);
				}
			}
			return hashSet.ToArray();
		}

		private IEnumerable<string> RecordFiles(string folder)
		{
			return (from path in files.Files(folder, "*.state*")
				where path.EndsWith(".state", StringComparison.Ordinal) || path.EndsWith(".state.pending", StringComparison.Ordinal) || path.EndsWith(".state.backup", StringComparison.Ordinal)
				select (!path.EndsWith(".pending", StringComparison.Ordinal)) ? ((!path.EndsWith(".backup", StringComparison.Ordinal)) ? path : path.Substring(0, path.Length - 7)) : path.Substring(0, path.Length - 8)).Distinct<string>(StringComparer.Ordinal).ToArray();
		}

		public void Remove(long world, string objectId, string field)
		{
			string text = RecordPath(world, objectId, field);
			Read(world, objectId, field, text);
			string[] array = new string[3] { ".pending", ".backup", "" };
			foreach (string text2 in array)
			{
				files.Delete(text + text2);
			}
		}

		public void ImportLocal(long world, string legacyDirectory)
		{
			string path = WorldDirectory(world);
			string path2 = Path.Combine(legacyDirectory, world.ToString(CultureInfo.InvariantCulture));
			if (!files.Exists(Path.Combine(path, "authority.key")) && Directory.Exists(path2))
			{
				ImportFrom(world, new AuthenticatedStateStore(legacyDirectory));
			}
		}

		public void ImportFrom(long world, AuthenticatedStateStore old, bool replaceExisting = false)
		{
			string path = WorldDirectory(world);
			string folder = old.WorldDirectory(world);
			byte[] key = old.Key(world, create: false);
			if (key.Length != 32)
			{
				return;
			}
			string path2 = Path.Combine(path, "authority.key");
			if (files.Exists(path2) && !((ReadOnlySpan<byte>)Key(world, create: false)).SequenceEqual((ReadOnlySpan<byte>)key))
			{
				throw new InvalidDataException("Authority world migration key conflict");
			}
			Dictionary<string, byte[]> dictionary = new Dictionary<string, byte[]>(StringComparer.Ordinal);
			foreach (string item in old.RecordFiles(folder))
			{
				Record record = old.Recover(item, (string p) => old.Decode(p, world, key));
				if (record != null)
				{
					old.Read(world, record.Object, record.Field);
					string path3 = old.RecordPath(world, record.Object, record.Field);
					dictionary[Path.GetFileName(path3)] = old.files.Read(path3, 4198400);
				}
			}
			foreach (KeyValuePair<string, byte[]> item2 in dictionary)
			{
				string path4 = Path.Combine(path, item2.Key);
				if (replaceExisting && files.Exists(path4) && !((ReadOnlySpan<byte>)files.Read(path4, 4198400)).SequenceEqual((ReadOnlySpan<byte>)item2.Value))
				{
					Recover(path4, (string p) => Decode(p, world, key));
					AtomicWrite(path4, item2.Value);
				}
				else
				{
					ImportFile(path4, item2.Value);
				}
			}
			ImportFile(Path.Combine(path, "authority.key.backup"), key);
			ImportFile(Path.Combine(path, "authority.key"), key);
		}

		private void ImportFile(string path, byte[] bytes)
		{
			if (files.Exists(path))
			{
				if (!((ReadOnlySpan<byte>)files.Read(path, 4198400)).SequenceEqual((ReadOnlySpan<byte>)bytes))
				{
					throw new InvalidDataException("Authority import conflicts with existing world state");
				}
				return;
			}
			if (files.Exists(path + ".pending"))
			{
				bool flag = false;
				try
				{
					flag = ((ReadOnlySpan<byte>)files.Read(path + ".pending", 4198400)).SequenceEqual((ReadOnlySpan<byte>)bytes);
				}
				catch (InvalidDataException)
				{
				}
				if (flag)
				{
					files.Promote(path + ".pending", path, path + ".backup");
					return;
				}
				Quarantine(path + ".pending");
			}
			AtomicWrite(path, bytes);
		}

		private void AtomicWrite(string path, byte[] bytes)
		{
			string text = path + ".pending";
			files.WriteNew(text, bytes);
			files.Promote(text, path, path + ".backup");
		}
	}
	public sealed class PurseLedger
	{
		public int Balance { get; private set; }

		public string Actor { get; private set; } = "";

		public string Token { get; private set; } = "";

		public string Epoch { get; private set; } = "";

		public string Fingerprint { get; private set; } = "";

		public long Delta { get; private set; }

		public bool Pending { get; private set; }

		public bool Committed { get; private set; }

		public bool Quarantined { get; private set; }

		public long ReservedAt { get; private set; }

		public PurseLedger(int initial)
		{
			Balance = Math.Max(initial, 0);
		}

		public bool Reserve(string actor, string token, string epoch, string fingerprint, long delta, out string reason)
		{
			reason = "InvalidReservation";
			if (string.IsNullOrEmpty(actor) || string.IsNullOrEmpty(token) || string.IsNullOrEmpty(epoch) || string.IsNullOrEmpty(fingerprint) || delta < -2147483647 || delta > int.MaxValue)
			{
				return false;
			}
			if (Actor == actor && Token == token && Epoch == epoch)
			{
				reason = ((Pending && Fingerprint == fingerprint && Delta == delta) ? "Reserved" : "AlreadyFinished");
				if (Pending && Fingerprint == fingerprint)
				{
					return Delta == delta;
				}
				return false;
			}
			if (Pending)
			{
				reason = "TraderBusy";
				return false;
			}
			if (Balance + Math.Min(delta, 0L) < 0)
			{
				reason = "TraderPoor";
				return false;
			}
			if (Balance + Math.Max(delta, 0L) > int.MaxValue)
			{
				reason = "PurseOverflow";
				return false;
			}
			Actor = actor;
			Token = token;
			Epoch = epoch;
			Fingerprint = fingerprint;
			Delta = delta;
			Balance += (int)Math.Min(delta, 0L);
			Pending = true;
			Committed = false;
			Quarantined = false;
			ReservedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
			reason = "Reserved";
			return true;
		}

		public bool Finish(string actor, string token, string epoch, bool committed, bool inventoryVerified = false)
		{
			if (!inventoryVerified || Quarantined || Actor != actor || Token != token || Epoch != epoch)
			{
				return false;
			}
			if (!Pending)
			{
				return Committed == committed;
			}
			Settle(committed);
			return true;
		}

		public bool FinishReported(string actor, string token, string epoch, bool committed)
		{
			if (Quarantined || Actor != actor || Token != token || Epoch != epoch)
			{
				return false;
			}
			if (Pending)
			{
				Settle(committed);
			}
			return true;
		}

		private void Settle(bool committed)
		{
			Balance += (int)(committed ? Math.Max(Delta, 0L) : (-Math.Min(Delta, 0L)));
			Pending = false;
			Committed = committed;
		}

		public bool QuarantineExpired(long now, int timeoutSeconds = 120)
		{
			if (!Pending || timeoutSeconds < 1 || now < ReservedAt || now - ReservedAt < timeoutSeconds)
			{
				return false;
			}
			Pending = false;
			Quarantined = true;
			return true;
		}

		public bool Refill(int next)
		{
			if (Pending || next < 0)
			{
				return false;
			}
			Balance = next;
			return true;
		}

		public string Encode()
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(2);
			binaryWriter.Write(Balance);
			binaryWriter.Write(Actor);
			binaryWriter.Write(Token);
			binaryWriter.Write(Epoch);
			binaryWriter.Write(Fingerprint);
			binaryWriter.Write(Delta);
			binaryWriter.Write(Pending);
			binaryWriter.Write(Committed);
			binaryWriter.Write(Quarantined);
			binaryWriter.Write(ReservedAt);
			return Convert.ToBase64String(memoryStream.ToArray());
		}

		public static PurseLedger Decode(string encoded)
		{
			if (encoded == null || encoded.Length > 4096)
			{
				throw new InvalidDataException("Ledger exceeds bounds.");
			}
			using MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(encoded));
			using BinaryReader binaryReader = new BinaryReader(memoryStream);
			int num = binaryReader.ReadInt32();
			if (num != 1 && num != 2)
			{
				throw new InvalidDataException("Unsupported ledger version.");
			}
			int num2 = binaryReader.ReadInt32();
			PurseLedger purseLedger = new PurseLedger(num2)
			{
				Actor = binaryReader.ReadString(),
				Token = binaryReader.ReadString(),
				Epoch = binaryReader.ReadString(),
				Fingerprint = binaryReader.ReadString(),
				Delta = binaryReader.ReadInt64(),
				Pending = binaryReader.ReadBoolean(),
				Committed = binaryReader.ReadBoolean()
			};
			if (num == 2)
			{
				purseLedger.Quarantined = binaryReader.ReadBoolean();
				purseLedger.ReservedAt = binaryReader.ReadInt64();
			}
			if (num2 < 0 || purseLedger.ReservedAt < 0 || (purseLedger.Quarantined && (purseLedger.Pending || purseLedger.Committed)) || purseLedger.Delta < -2147483647 || purseLedger.Delta > int.MaxValue || (purseLedger.Pending && num2 + Math.Abs(purseLedger.Delta) > int.MaxValue) || purseLedger.Actor.Length > 128 || purseLedger.Token.Length > 128 || purseLedger.Epoch.Length > 128 || purseLedger.Fingerprint.Length > 128 || memoryStream.Position != memoryStream.Length || (purseLedger.Pending && (purseLedger.Actor.Length == 0 || purseLedger.Token.Length == 0 || purseLedger.Epoch.Length == 0 || purseLedger.Fingerprint.Length == 0)))
			{
				throw new InvalidDataException("Invalid ledger state.");
			}
			return purseLedger;
		}
	}
	public static class RefillTiming
	{
		public enum Operation
		{
			AuthorityRead,
			AuthorityWrite,
			LocalRead,
			LocalWrite,
			CloudRead,
			CloudWrite,
			Promote,
			Flush,
			CloudFinish
		}

		public struct Cost
		{
			public long Ticks;

			public int Count;
		}

		public struct Result
		{
			public long TotalTicks;

			public int Day;

			public int Scanned;

			public int Traders;

			public int Refilled;

			public Cost AuthorityRead;

			public Cost AuthorityWrite;

			public Cost LocalRead;

			public Cost LocalWrite;

			public Cost CloudRead;

			public Cost CloudWrite;

			public Cost Promote;

			public Cost Flush;

			public Cost CloudFinish;
		}

		public readonly struct Span : IDisposable
		{
			private readonly Operation operation;

			private readonly long start;

			private readonly bool enabled;

			internal Span(Operation operation, bool enabled)
			{
				this.operation = operation;
				this.enabled = enabled;
				start = (enabled ? Stopwatch.GetTimestamp() : 0);
			}

			public void Dispose()
			{
				if (enabled)
				{
					long ticks = Stopwatch.GetTimestamp() - start;
					switch (operation)
					{
					case Operation.AuthorityRead:
						Add(ref result.AuthorityRead, ticks);
						break;
					case Operation.AuthorityWrite:
						Add(ref result.AuthorityWrite, ticks);
						break;
					case Operation.LocalRead:
						Add(ref result.LocalRead, ticks);
						break;
					case Operation.LocalWrite:
						Add(ref result.LocalWrite, ticks);
						break;
					case Operation.CloudRead:
						Add(ref result.CloudRead, ticks);
						break;
					case Operation.CloudWrite:
						Add(ref result.CloudWrite, ticks);
						break;
					case Operation.Promote:
						Add(ref result.Promote, ticks);
						break;
					case Operation.Flush:
						Add(ref result.Flush, ticks);
						break;
					case Operation.CloudFinish:
						Add(ref result.CloudFinish, ticks);
						break;
					}
				}
			}
		}

		[ThreadStatic]
		private static bool active;

		[ThreadStatic]
		private static long started;

		[ThreadStatic]
		private static Result result;

		public static void Begin()
		{
			result = default(Result);
			started = Stopwatch.GetTimestamp();
			active = true;
		}

		public static Result End()
		{
			result.TotalTicks = Stopwatch.GetTimestamp() - started;
			active = false;
			return result;
		}

		public static void SetDay(int day)
		{
			if (active)
			{
				result.Day = day;
			}
		}

		public static void Scanned()
		{
			if (active)
			{
				result.Scanned++;
			}
		}

		public static void Trader()
		{
			if (active)
			{
				result.Traders++;
			}
		}

		public static void Refilled()
		{
			if (active)
			{
				result.Refilled++;
			}
		}

		public static Span Measure(Operation operation)
		{
			return new Span(operation, active);
		}

		private static void Add(ref Cost cost, long ticks)
		{
			cost.Ticks += ticks;
			cost.Count++;
		}
	}
	public static class SellCursor
	{
		public static int Move(int current, int count, int direction)
		{
			if (count > 0)
			{
				return Math.Max(0, Math.Min(count - 1, (current >= 0) ? (current + Math.Sign(direction)) : 0));
			}
			return -1;
		}
	}
	public sealed class HeldItem
	{
		public object Id { get; }

		public string Prefab { get; }

		public int Stack { get; }

		public int Quality { get; }

		public int MaxStack { get; }

		public HeldItem(object id, string prefab, int stack, int quality, int maxStack)
		{
			Id = id ?? throw new ArgumentNullException("id");
			Prefab = prefab ?? throw new ArgumentNullException("prefab");
			Stack = stack;
			Quality = quality;
			MaxStack = maxStack;
		}
	}
	public enum SellKind
	{
		Single,
		Stack,
		Combined
	}
	public sealed class SellSettings
	{
		public float PriceFactor { get; }

		public float QualityMultiplier { get; }

		public SellSettings(float priceFactor, float qualityMultiplier)
		{
			PriceFactor = priceFactor;
			QualityMultiplier = qualityMultiplier;
		}
	}
	public sealed class SellOffer
	{
		private readonly List<object> sources = new List<object>();

		public SellKind Kind { get; }

		public string Prefab { get; }

		public int Stack { get; internal set; }

		public int Amount { get; internal set; }

		public int Quality { get; }

		public int PricePerItem { get; }

		public int Price { get; internal set; }

		public string Currency { get; }

		public IReadOnlyList<object> Sources => sources;

		public int Lots
		{
			get
			{
				if (Kind != SellKind.Single)
				{
					if (Kind != SellKind.Combined)
					{
						return Amount / Math.Max(Stack, 1);
					}
					return Amount;
				}
				return 1;
			}
		}

		internal SellOffer(SellKind kind, string prefab, int stack, int amount, int quality, int pricePerItem, int price, string currency)
		{
			Kind = kind;
			Prefab = prefab;
			Stack = stack;
			Amount = amount;
			Quality = quality;
			PricePerItem = pricePerItem;
			Price = price;
			Currency = currency;
		}

		internal void AddSource(object source)
		{
			sources.Add(source);
		}
	}
	public static class SellPlanner
	{
		public static List<SellOffer> Plan(IEnumerable<HeldItem> held, SellPriceTable table, SellSettings settings, Func<string, string?> resolveCurrency)
		{
			List<SellOffer> list = new List<SellOffer>();
			foreach (HeldItem item in held)
			{
				int configuredQuality;
				IReadOnlyDictionary<int, SellPrice> readOnlyDictionary = table.Lookup(item.Prefab, item.Quality, out configuredQuality);
				if (readOnlyDictionary == null)
				{
					continue;
				}
				foreach (int item2 in readOnlyDictionary.Keys.OrderBy((int x) => x))
				{
					SellPrice sellPrice = readOnlyDictionary[item2];
					string text = resolveCurrency(sellPrice.Currency);
					if (text != null && !string.Equals(item.Prefab, text, StringComparison.Ordinal))
					{
						if (item2 == 1)
						{
							Add(list, item, (item.MaxStack == 1) ? 1 : item.Stack, sellPrice.Price, settings, configuredQuality, (item.MaxStack != 1) ? SellKind.Combined : SellKind.Single, text);
						}
						else
						{
							Add(list, item, item2, sellPrice.Price, settings, configuredQuality, SellKind.Stack, text);
						}
					}
				}
			}
			list.RemoveAll((SellOffer offer) => offer.Amount != 0 && offer.Amount < offer.Stack);
			return list;
		}

		private static void Add(List<SellOffer> offers, HeldItem item, int itemStack, int itemPrice, SellSettings settings, int configuredQuality, SellKind kind, string currency)
		{
			int effectiveQuality = ((configuredQuality > 0) ? configuredQuality : item.Quality);
			int adjustedPrice = itemPrice;
			if ((kind != SellKind.Stack && settings.QualityMultiplier != 0f && configuredQuality == 0 && item.Quality > 1 && !TradeAmounts.TryGetQualityPrice(itemPrice, item.Quality, settings.QualityMultiplier, out adjustedPrice)) || !TradeAmounts.TryGetPrice(adjustedPrice, (kind != SellKind.Combined) ? 1 : itemStack, settings.PriceFactor, out var price, roundUp: false))
			{
				return;
			}
			if (kind == SellKind.Single)
			{
				SellOffer sellOffer = new SellOffer(kind, item.Prefab, itemStack, 0, effectiveQuality, adjustedPrice, price, currency);
				sellOffer.AddSource(item.Id);
				offers.Add(sellOffer);
				return;
			}
			if (kind == SellKind.Stack)
			{
				SellOffer sellOffer2 = offers.Find((SellOffer o) => o.Kind == kind && o.Stack == itemStack && o.Prefab == item.Prefab && o.Quality == effectiveQuality && o.Price == price && o.Currency == currency);
				if (sellOffer2 != null)
				{
					sellOffer2.Amount = TradeAmounts.ClampBalance((long)sellOffer2.Amount + (long)item.Stack);
					sellOffer2.AddSource(item.Id);
				}
				else
				{
					SellOffer sellOffer3 = new SellOffer(kind, item.Prefab, itemStack, item.Stack, effectiveQuality, adjustedPrice, price, currency);
					sellOffer3.AddSource(item.Id);
					offers.Add(sellOffer3);
				}
				return;
			}
			SellOffer sellOffer4 = offers.Find((SellOffer o) => o.Kind == kind && o.Prefab == item.Prefab && o.Quality == effectiveQuality && o.Stack == 1 && o.PricePerItem == adjustedPrice && o.Currency == currency);
			if (sellOffer4 != null)
			{
				int num = TradeAmounts.ClampBalance((long)sellOffer4.Amount + (long)itemStack);
				if (!TradeAmounts.TryGetPrice(sellOffer4.PricePerItem, num, settings.PriceFactor, out var price2, roundUp: false))
				{
					offers.Remove(sellOffer4);
					return;
				}
				sellOffer4.Amount = num;
				sellOffer4.Price = price2;
				sellOffer4.AddSource(item.Id);
			}
			else
			{
				SellOffer sellOffer5 = new SellOffer(kind, item.Prefab, 1, itemStack, effectiveQuality, adjustedPrice, price, currency);
				sellOffer5.AddSource(item.Id);
				offers.Add(sellOffer5);
			}
		}
	}
	public sealed class SellPrice
	{
		public int Price { get; }

		public string Currency { get; }

		public SellPrice(int price, string currency)
		{
			Price = price;
			Currency = currency ?? string.Empty;
		}
	}
	public sealed class SellPriceTable
	{
		private readonly Dictionary<string, Dictionary<int, SellPrice>> prices;

		public static SellPriceTable Empty { get; } = new SellPriceTable(new Dictionary<string, Dictionary<int, SellPrice>>());

		public int Count => prices.Count;

		private SellPriceTable(Dictionary<string, Dictionary<int, SellPrice>> prices)
		{
			this.prices = prices;
		}

		public static SellPriceTable Build(IEnumerable<TradeEntry> entries, ITradeContext context)
		{
			Dictionary<string, Dictionary<int, SellPrice>> dictionary = new Dictionary<string, Dictionary<int, SellPrice>>(StringComparer.Ordinal);
			foreach (TradeEntry entry in entries)
			{
				if (EntryAvailability.CanPrice(entry, context))
				{
					string key = Key(entry.Prefab, entry.Quality);
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = new Dictionary<int, SellPrice>();
						dictionary.Add(key, value);
					}
					value[entry.Stack] = new SellPrice(entry.Price, entry.Currency);
				}
			}
			return new SellPriceTable(dictionary);
		}

		public IReadOnlyDictionary<int, SellPrice>? Lookup(string prefab, int itemQuality, out int configuredQuality)
		{
			configuredQuality = itemQuality;
			if (prices.TryGetValue(Key(prefab, itemQuality), out Dictionary<int, SellPrice> value))
			{
				return value;
			}
			configuredQuality = 0;
			if (!prices.TryGetValue(Key(prefab, 0), out Dictionary<int, SellPrice> value2))
			{
				return null;
			}
			return value2;
		}

		private static string Key(string prefab, int quality)
		{
			return prefab + "|" + quality;
		}
	}
	public static class ServiceRules
	{
		public static bool RepairPrice(int basePrice, int quality, float durability, float maximum, float factor, out int price)
		{
			price = 0;
			if (basePrice <= 0 || quality <= 0 || float.IsNaN(durability) || float.IsInfinity(durability) || float.IsNaN(maximum) || float.IsInfinity(maximum) || maximum <= 0f || durability < 0f || durability >= maximum || float.IsNaN(factor) || float.IsInfinity(factor) || factor < 0f)
			{
				return false;
			}
			double num = Math.Ceiling((double)basePrice * (double)quality * (double)((maximum - durability) / maximum) * (double)factor);
			if (num > 2147483647.0)
			{
				return false;
			}
			price = Math.Max(1, (int)num);
			return true;
		}
	}
	public static class TradeAmounts
	{
		public const int MaximumSliderLots = 16777216;

		public static bool TryGetItemCount(int lotSize, int lots, out int amount)
		{
			long num = (long)lotSize * (long)lots;
			amount = 0;
			if (lotSize <= 0 || lots <= 0 || num > int.MaxValue)
			{
				return false;
			}
			amount = (int)num;
			return true;
		}

		public static bool TryGetPrice(int pricePerLot, int lots, float factor, out int price, bool roundUp = true)
		{
			return TryGetPrice(pricePerLot, lots, Math.Round(factor, 2), out price, roundUp);
		}

		public static bool TryGetPrice(int pricePerLot, int lots, double factor, out int price, bool roundUp = true)
		{
			price = 0;
			if (pricePerLot <= 0 || lots <= 0 || double.IsNaN(factor) || double.IsInfinity(factor) || factor < 0.0 || factor > 2147483647.0)
			{
				return false;
			}
			decimal d = (decimal)pricePerLot * (decimal)lots * ToDecimal(factor);
			decimal num = Math.Max(roundUp ? decimal.Ceiling(d) : decimal.Floor(d), 1m);
			if (num > 2147483647m)
			{
				return false;
			}
			price = (int)num;
			return true;
		}

		public static bool TryGetQualityPrice(int basePrice, int quality, float multiplier, out int price)
		{
			price = 0;
			if (basePrice <= 0 || quality <= 0 || float.IsNaN(multiplier) || float.IsInfinity(multiplier) || Math.Abs((double)multiplier) > 2147483647.0)
			{
				return false;
			}
			decimal num = (decimal)basePrice * (1m + ToDecimal(multiplier) * (decimal)((long)quality - 1L));
			if (num < 1m || num > 2147483647m)
			{
				return false;
			}
			price = (int)num;
			return true;
		}

		public static decimal ToDecimal(double value)
		{
			if (double.IsNaN(value) || double.IsInfinity(value) || Math.Abs(value) < 1E-09)
			{
				return 0m;
			}
			return decimal.Parse(value.ToString("R", CultureInfo.InvariantCulture), NumberStyles.Float, CultureInfo.InvariantCulture);
		}

		public static decimal ToDecimal(float value)
		{
			if (float.IsNaN(value) || float.IsInfinity(value) || Math.Abs(value) < 1E-09f)
			{
				return 0m;
			}
			return decimal.Parse(value.ToString("R", CultureInfo.InvariantCulture), NumberStyles.Float, CultureInfo.InvariantCulture);
		}

		public static int MaximumBuyLots(int lotSize, int pricePerLot, int currency, int capacity)
		{
			if (lotSize <= 0 || pricePerLot <= 0 || currency <= 0 || capacity <= 0)
			{
				return 0;
			}
			return Math.Min(16777216, Math.Min(capacity / lotSize, currency / pricePerLot));
		}

		public static int MaximumSellLots(int lotSize, int pricePerLot, int availableItems, float factor, int budget)
		{
			return MaximumSellLots(lotSize, pricePerLot, availableItems, Math.Round(factor, 2), budget);
		}

		public static int MaximumSellLots(int lotSize, int pricePerLot, int availableItems, double factor, int budget)
		{
			if (lotSize <= 0 || pricePerLot <= 0 || availableItems <= 0 || budget <= 0)
			{
				return 0;
			}
			int num = 0;
			int num2 = Math.Min(16777216, availableItems / lotSize);
			while (num < num2)
			{
				int num3 = num + (num2 - num + 1) / 2;
				if (TryGetPrice(pricePerLot, num3, factor, out var price, roundUp: false) && price <= budget)
				{
					num = num3;
				}
				else
				{
					num2 = num3 - 1;
				}
			}
			return num;
		}

		public static bool TryEncodeStack(int stack, int quality, int multiplier, out int encoded)
		{
			encoded = 0;
			long num = stack + (long)multiplier * (long)quality;
			if (multiplier <= 1 || stack <= 0 || stack >= multiplier || quality < 0 || num > int.MaxValue)
			{
				return false;
			}
			encoded = (int)num;
			return true;
		}

		public static bool TryEncodeStack(int stack, int quality, out int encoded)
		{
			return TryEncodeStack(stack, quality, 1000000, out encoded);
		}

		public static void DecodeStack(int encoded, out int stack, out int quality)
		{
			stack = encoded % 1000000;
			quality = encoded / 1000000;
		}

		public static int ClampBalance(long amount)
		{
			return (int)Math.Max(0L, Math.Min(2147483647L, amount));
		}
	}
	public sealed class JournalEntry
	{
		public string Token = "";

		public string Actor = "";

		public string BeforeInventory = "";

		public string AfterInventory = "";

		public long World;

		public byte Phase;

		public bool Consumed;

		public byte[] Request = Array.Empty<byte>();
	}
	public sealed class TradeJournal
	{
		private readonly string directory;

		public TradeJournal(string directory)
		{
			this.directory = Path.GetFullPath(directory);
		}

		private string PathFor(string token)
		{
			if (!Guid.TryParseExact(token, "N", out var _))
			{
				throw new InvalidDataException("Invalid receipt token");
			}
			return Path.Combine(directory, token + ".receipt");
		}

		public void Save(JournalEntry entry)
		{
			if (entry == null || entry.World == 0L || entry.Actor.Length == 0 || entry.Actor.Length > 128 || entry.Phase > 3 || entry.Request.Length > 98304 || entry.BeforeInventory.Length > 2097152 || entry.AfterInventory.Length > 2097152)
			{
				throw new InvalidDataException("Invalid journal entry");
			}
			string text = PathFor(entry.Token);
			Directory.CreateDirectory(directory);
			if (!File.Exists(text))
			{
				int num = 0;
				foreach (JournalEntry item in Read())
				{
					if (item.World == entry.World && ++num >= 256)
					{
						throw new InvalidDataException("Journal receipt bound");
					}
				}
			}
			byte[] array;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
				binaryWriter.Write(3);
				binaryWriter.Write(entry.Token);
				binaryWriter.Write(entry.World);
				binaryWriter.Write(entry.Actor);
				binaryWriter.Write(entry.Phase);
				binaryWriter.Write(entry.Request.Length);
				binaryWriter.Write(entry.Request);
				binaryWriter.Write(entry.BeforeInventory);
				binaryWriter.Write(entry.AfterInventory);
				binaryWriter.Write(entry.Consumed);
				array = memoryStream.ToArray();
			}
			string text2 = text + ".pending";
			using (FileStream fileStream = new FileStream(text2, FileMode.Create, FileAccess.Write, FileShare.None))
			{
				using (SHA256 sHA = SHA256.Create())
				{
					byte[] array2 = sHA.ComputeHash(array);
					fileStream.Write(array2, 0, array2.Length);
				}
				fileStream.Write(array, 0, array.Length);
				fileStream.Flush(flushToDisk: true);
			}
			if (File.Exists(text))
			{
				File.Replace(text2, text, null);
			}
			else
			{
				File.Move(text2, text);
			}
		}

		public IReadOnlyList<JournalEntry> Read()
		{
			List<JournalEntry> list = new List<JournalEntry>();
			if (!Directory.Exists(directory))
			{
				return list;
			}
			using (IEnumerator<string> enumerator = Directory.EnumerateFiles(directory, "*.pending").GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					_ = enumerator.Current;
					throw new InvalidDataException("Incomplete journal write");
				}
			}
			Dictionary<long, int> dictionary = new Dictionary<long, int>();
			Dictionary<long, long> dictionary2 = new Dictionary<long, long>();
			foreach (string item in Directory.EnumerateFiles(directory, "*.receipt"))
			{
				long length = new FileInfo(item).Length;
				if (length < 40 || length > 4400000)
				{
					throw new InvalidDataException("Journal size");
				}
				byte[] array = File.ReadAllBytes(item);
				if (array.Length < 40 || array.Length > 4400000)
				{
					throw new InvalidDataException("Journal size");
				}
				byte[] array2 = new byte[array.Length - 32];
				Buffer.BlockCopy(array, 32, array2, 0, array2.Length);
				using (SHA256 sHA = SHA256.Create())
				{
					byte[] array3 = sHA.ComputeHash(array2);
					for (int i = 0; i < 32; i++)
					{
						if (array3[i] != array[i])
						{
							throw new InvalidDataException("Journal checksum");
						}
					}
				}
				using MemoryStream memoryStream = new MemoryStream(array2);
				using BinaryReader binaryReader = new BinaryReader(memoryStream);
				int num = binaryReader.ReadInt32();
				if (num < 1 || num > 3)
				{
					throw new InvalidDataException("Journal version");
				}
				JournalEntry journalEntry = new JournalEntry
				{
					Token = binaryReader.ReadString(),
					World = binaryReader.ReadInt64(),
					Actor = binaryReader.ReadString(),
					Phase = binaryReader.ReadByte()
				};
				int num2 = binaryReader.ReadInt32();
				if (num2 < 0 || num2 > 98304)
				{
					throw new InvalidDataException("Journal request");
				}
				journalEntry.Request = binaryReader.ReadBytes(num2);
				journalEntry.BeforeInventory = binaryReader.ReadString();
				if (num >= 2)
				{
					journalEntry.AfterInventory = binaryReader.ReadString();
				}
				journalEntry.Consumed = ((num >= 3) ? binaryReader.ReadBoolean() : (journalEntry.Phase == 2));
				if (journalEntry.Request.Length != num2 || memoryStream.Position != memoryStream.Length || journalEntry.Actor.Length == 0 || journalEntry.Actor.Length > 128 || journalEntry.World == 0L || journalEntry.Phase > 3 || journalEntry.BeforeInventory.Length > 2097152 || journalEntry.AfterInventory.Length > 2097152 || !string.Equals(item, PathFor(journalEntry.Token), StringComparison.OrdinalIgnoreCase))
				{
					throw new InvalidDataException("Journal identity");
				}
				dictionary.TryGetValue(journalEntry.World, out var value);
				dictionary2.TryGetValue(journalEntry.World, out var value2);
				if (++value > 256 || (value2 += length) > 67108864)
				{
					throw new InvalidDataException("Journal world bound");
				}
				dictionary[journalEntry.World] = value;
				dictionary2[journalEntry.World] = value2;
				list.Add(journalEntry);
			}
			return list;
		}

		public void Remove(string token, bool characterSaved = false)
		{
			if (!characterSaved)
			{
				foreach (JournalEntry item in Read())
				{
					if (item.Token == token && (item.Phase == 1 || item.Phase == 2))
					{
						throw new InvalidOperationException("Character-save proof required before discarding inventory evidence");
					}
				}
			}
			File.Delete(PathFor(token));
		}
	}
	public static class TradeQuoteRules
	{
		public static bool BuyMatches(IEnumerable<TradeEntry> entries, ITradeContext context, DiscoveryRule discovery, bool personalStateAvailable, string prefab, int amount, int quality, int price, string currency, int defaultQuality, float factor, Func<string, string?> resolveCurrency)
		{
			if (amount <= 0 || quality <= 0 || price <= 0 || string.IsNullOrEmpty(currency))
			{
				return false;
			}
			int price2;
			return entries.Any((TradeEntry entry) => entry.Prefab == prefab && entry.Stack == amount && ((entry.Quality > 0) ? entry.Quality : defaultQuality) == quality && (personalStateAvailable || !NeedsPersonalKeys(entry)) && EntryAvailability.CanOffer(entry, context, discovery) && resolveCurrency(entry.Currency) == currency && TradeAmounts.TryGetPrice(entry.Price, 1, factor, out price2) && price2 == price);
		}

		public static bool SellMatches(IEnumerable<TradeEntry> entries, ITradeContext context, bool personalStateAvailable, string prefab, int amount, int quality, int lotSize, int maxStack, int price, string currency, float factor, float qualityMultiplier, Func<string, string?> resolveCurrency)
		{
			if (amount <= 0 || quality <= 0 || lotSize <= 0 || maxStack <= 0 || price <= 0 || string.IsNullOrEmpty(currency))
			{
				return false;
			}
			SellPriceTable table = SellPriceTable.Build(entries.Where((TradeEntry entry) => personalStateAvailable || !NeedsPersonalKeys(entry)), context);
			return SellPlanner.Plan(new HeldItem[1]
			{
				new HeldItem(new object(), prefab, amount, quality, maxStack)
			}, table, new SellSettings(factor, qualityMultiplier), resolveCurrency).Any((SellOffer offer) => offer.Stack == lotSize && offer.Price == price && offer.Currency == currency && ((offer.Kind != SellKind.Single) ? ((offer.Kind != SellKind.Stack) ? (amount == offer.Amount) : (amount == offer.Stack)) : (amount == 1)));
		}

		private static bool NeedsPersonalKeys(TradeEntry entry)
		{
			if (TradeEntry.SplitKeys(entry.RequiredPlayerKey).Count == 0)
			{
				return TradeEntry.SplitKeys(entry.NotRequiredPlayerKey).Count != 0;
			}
			return true;
		}
	}
	public sealed class TradeRecovery
	{
		private readonly long world;

		private readonly string actor;

		private bool awaitingReservation = true;

		private bool inFlight;

		private double retryAt;

		public bool? Outcome { get; private set; } = false;

		public bool Done { get; private set; }

		public TradeRecovery(long world, string actor)
		{
			if (world == 0L || string.IsNullOrEmpty(actor))
			{
				throw new ArgumentException("Missing recovery identity.");
			}
			this.world = world;
			this.actor = actor;
		}

		public void ReservationEnded()
		{
			awaitingReservation = false;
		}

		public void InventoryStarting()
		{
			awaitingReservation = false;
			Outcome = null;
		}

		public void InventoryFinished(bool success)
		{
			awaitingReservation = false;
			Outcome = success;
		}

		public bool TryDispatch(long currentWorld, string currentActor, double now)
		{
			if (Done || awaitingReservation || inFlight || !Outcome.HasValue || currentWorld != world || currentActor != actor || now < retryAt)
			{
				return false;
			}
			inFlight = true;
			retryAt = now + 2.0;
			return true;
		}

		public void Reply(bool acknowledged)
		{
			inFlight = false;
			Done |= acknowledged;
		}

		public void Suspend()
		{
			awaitingReservation = false;
			inFlight = false;
		}

		public static bool CanConfirm(JournalEntry entry, string loadedInventory)
		{
			if (entry.Phase == 2 && entry.AfterInventory.Length > 0)
			{
				return entry.AfterInventory == loadedInventory;
			}
			return false;
		}
	}
}
namespace ExtraPotions.Barter.Pricing
{
	public static class PriceCurve
	{
		public static float BuyFactor(int balance, PurseRules rules)
		{
			if (!rules.Enabled || !rules.Flexible)
			{
				return 1f;
			}
			rules.Range(out var minimum, out var maximum);
			if (balance < minimum)
			{
				float t = ((minimum > 0) ? Clamp01((float)balance / (float)minimum) : 1f);
				return RoundToPercent(Lerp(rules.Markup, 1f, t));
			}
			float t2 = Clamp01((float)(balance - minimum) / (float)Math.Max(maximum - minimum, 1));
			return RoundToPercent(Lerp(1f, rules.Discount, t2));
		}

		public static float SellFactor(int balance, PurseRules rules)
		{
			if (!rules.Enabled || !rules.Flexible)
			{
				return 1f;
			}
			rules.Range(out var minimum, out var maximum);
			if (balance < minimum)
			{
				float t = ((minimum > 0) ? Clamp01((float)balance / (float)minimum) : 1f);
				return RoundToPercent(Lerp(rules.Discount, 1f, t));
			}
			float t2 = Clamp01((float)(balance - minimum) / (float)Math.Max(maximum - minimum, 1));
			return RoundToPercent(Lerp(1f, rules.Markup, t2));
		}

		public static float RoundToPercent(float factor)
		{
			if (float.IsNaN(factor) || float.IsInfinity(factor) || factor < 0f)
			{
				return 1f;
			}
			return (float)(Math.Round((double)factor * 100.0) / 100.0);
		}

		public static string Describe(float factor, bool reversed, out bool favourable)
		{
			favourable = true;
			if (factor == 1f)
			{
				return string.Empty;
			}
			favourable = (reversed && factor < 1f) || (!reversed && factor > 1f);
			double num = (factor - 1f) * 100f;
			return ((num >= 0.0) ? "+" : "-") + Math.Abs(Math.Round(num)).ToString("0", CultureInfo.InvariantCulture);
		}

		private static float Clamp01(float value)
		{
			if (!(value < 0f))
			{
				if (!(value > 1f))
				{
					return value;
				}
				return 1f;
			}
			return 0f;
		}

		private static float Lerp(float a, float b, float t)
		{
			return a + (b - a) * Clamp01(t);
		}
	}
	public static class PurseRefill
	{
		public static int Initial(PurseRules rules)
		{
			rules.Range(out var minimum, out var _);
			return minimum;
		}

		public static bool TryReplenish(int current, int lastDay, int today, PurseRules rules, out int next)
		{
			next = current;
			if (today - lastDay < Math.Max(rules.ReplenishDays, 1))
			{
				return false;
			}
			rules.Range(out var minimum, out var maximum);
			if (current >= maximum && rules.DailyDecrease <= 0)
			{
				return false;
			}
			next = ((current >= maximum) ? Math.Max(maximum, current - Math.Max(rules.DailyDecrease, 0)) : Math.Max(minimum, Math.Min(maximum, TradeAmounts.ClampBalance((long)current + (long)rules.DailyIncrease))));
			return true;
		}
	}
	public sealed class PurseRules
	{
		public bool Enabled { get; set; }

		public bool Flexible { get; set; }

		public int Minimum { get; set; }

		public int Maximum { get; set; }

		public int DailyIncrease { get; set; }

		public int DailyDecrease { get; set; }

		public float Discount { get; set; }

		public float Markup { get; set; }

		public int ReplenishDays { get; set; }

		public static PurseRules Defaults()
		{
			return new PurseRules
			{
				Enabled = BarterSettings.Purse.Enabled.Default,
				Flexible = BarterSettings.Purse.FlexiblePricing.Default,
				Minimum = BarterSettings.Purse.MinimumBalance.Default,
				Maximum = BarterSettings.Purse.MaximumBalance.Default,
				DailyIncrease = BarterSettings.Purse.DailyIncrease.Default,
				DailyDecrease = BarterSettings.Purse.DailyDecrease.Default,
				Discount = BarterSettings.Purse.Discount.Default,
				Markup = BarterSettings.Purse.Markup.Default,
				ReplenishDays = BarterSettings.Purse.ReplenishDays.Default
			};
		}

		internal void Range(out int minimum, out int maximum)
		{
			minimum = Math.Max(Minimum, 0);
			maximum = Math.Max(Maximum, minimum);
		}
	}
}
namespace ExtraPotions.Barter.Lists
{
	public static class ListEditRules
	{
		public static string Revision(IReadOnlyDictionary<string, string> files)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true);
			using SHA256 sHA = SHA256.Create();
			foreach (KeyValuePair<string, string> item in files.OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> p) => p.Key, StringComparer.Ordinal))
			{
				binaryWriter.Write(item.Key);
				binaryWriter.Write(item.Value);
			}
			binaryWriter.Flush();
			return Convert.ToBase64String(sHA.ComputeHash(memoryStream.ToArray()));
		}

		public static string OwnedPath(string root, string relative)
		{
			if (string.IsNullOrWhiteSpace(relative) || relative.Contains("..") || relative.Contains("\\") || Path.IsPathRooted(relative))
			{
				throw new ArgumentException("Invalid list path.");
			}
			string text = Path.GetFullPath(root).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;
			string fullPath = Path.GetFullPath(Path.Combine(text, relative.Replace('/', Path.DirectorySeparatorChar)));
			if (!fullPath.StartsWith(text, StringComparison.OrdinalIgnoreCase))
			{
				throw new ArgumentException("List outside config root.");
			}
			string text2 = fullPath;
			while (text2 != null && text2.Length >= text.TrimEnd(Path.DirectorySeparatorChar).Length)
			{
				if ((File.Exists(text2) || Directory.Exists(text2)) && (File.GetAttributes(text2) & FileAttributes.ReparsePoint) != FileAttributes.None)
				{
					throw new IOException("Linked config paths cannot be edited.");
				}
				text2 = Path.GetDirectoryName(text2);
			}
			return fullPath;
		}

		public static bool AtomicReplace(string path, string expected, string replacement)
		{
			if (!File.Exists(path) || File.ReadAllText(path) != expected)
			{
				return false;
			}
			string text = path + ".barter-edit-" + Guid.NewGuid().ToString("N");
			string destinationBackupFileName = path + ".barter-backup-" + Guid.NewGuid().ToString("N");
			try
			{
				using (FileStream fileStream = new FileStream(text, FileMode.CreateNew, FileAccess.Write, FileShare.None))
				{
					byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(replacement);
					fileStream.Write(bytes, 0, bytes.Length);
					fileStream.Flush(flushToDisk: true);
				}
				if (File.ReadAllText(path) != expected)
				{
					return false;
				}
				File.Replace(text, path, destinationBackupFileName);
				return true;
			}
			finally
			{
				if (File.Exists(text))
				{
					File.Delete(text);
				}
			}
		}
	}
	public sealed class ListFileName
	{
		public string FileName { get; }

		public string Trader { get; }

		public ListKind Kind { get; }

		public string Identifier { get; }

		public ListFormat Format { get; }

		public string ListKey => TraderNames.ListKey(Trader, Kind);

		private ListFileName(string fileName, string trader, ListKind kind, string identifier, ListFormat format)
		{
			FileName = fileName;
			Trader = trader;
			Kind = kind;
			Identifier = identifier;
			Format = format;
		}

		public static bool IsSupportedExtension(string? extension)
		{
			if (!string.Equals(extension, ".json", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".yaml", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".yml", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(extension, ".csv", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		public static bool TryParse(string? fileName, out ListFileName? parsed, bool allowUnprefixed = false)
		{
			parsed = null;
			if (string.IsNullOrWhiteSpace(fileName))
			{
				return false;
			}
			string fileName2 = Path.GetFileName(fileName);
			string extension = Path.GetExtension(fileName2);
			if (!IsSupportedExtension(extension))
			{
				return false;
			}
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName2);
			bool flag = fileNameWithoutExtension.StartsWith("Barter.", StringComparison.OrdinalIgnoreCase);
			if (!flag && !allowUnprefixed)
			{
				return false;
			}
			string[] array = (flag ? fileNameWithoutExtension.Substring("Barter.".Length) : fileNameWithoutExtension).Split('.');
			int num = 1;
			while (num < array.Length)
			{
				ListKind kind;
				if (string.Equals(array[num], "Buy", StringComparison.OrdinalIgnoreCase))
				{
					kind = ListKind.Buy;
				}
				else
				{
					if (!string.Equals(array[num], "Sell", StringComparison.OrdinalIgnoreCase))
					{
						num++;
						continue;
					}
					kind = ListKind.Sell;
				}
				string text = TraderNames.Normalize(string.Join(".", array.Take(num)));
				if (text.Length == 0)
				{
					return false;
				}
				string identifier = string.Join(".", array.Skip(num + 1));
				ListFormat format = (string.Equals(extension, ".csv", StringComparison.OrdinalIgnoreCase) ? ListFormat.Csv : (string.Equals(extension, ".json", StringComparison.OrdinalIgnoreCase) ? ListFormat.Json : ListFormat.Yaml));
				parsed = new ListFileName(fileName2, text, kind, identifier, format);
				return true;
			}
			return false;
		}

		public static IEnumerable<ListSourceFile> Order(IEnumerable<ListSourceFile> files)
		{
			return files.OrderBy((ListSourceFile file) => (!file.Embedded) ? 1 : 0).ThenBy<ListSourceFile, string>((ListSourceFile file) => file.FileName, StringComparer.OrdinalIgnoreCase).ThenBy<ListSourceFile, string>((ListSourceFile file) => file.FileName, StringComparer.Ordinal);
		}
	}
	public sealed class ListSourceFile
	{
		public string FileName { get; }

		public bool Embedded { get; }

		public ListSourceFile(string fileName, bool embedded)
		{
			FileName = fileName ?? throw new ArgumentNullException("fileName");
			Embedded = embedded;
		}
	}
	public enum ListKind
	{
		Buy,
		Sell
	}
	public enum ListFormat
	{
		Yaml,
		Json,
		Csv
	}
	public sealed class ListContribution
	{
		public ListFileName Name { get; }

		public IReadOnlyList<TradeEntry> Entries { get; }

		public string SourceName { get; }

		public bool Embedded { get; }

		public ListContribution(ListFileName name, IReadOnlyList<TradeEntry> entries, string? sourceName = null, bool embedded = false)
		{
			Name = name ?? throw new ArgumentNullException("name");
			Entries = entries ?? throw new ArgumentNullException("entries");
			SourceName = (string.IsNullOrEmpty(sourceName) ? name.FileName : sourceName);
			Embedded = embedded;
		}
	}
	public sealed class TradeBook
	{
		private static readonly IReadOnlyList<TradeEntry> None = Array.Empty<TradeEntry>();

		private readonly Dictionary<string, List<TradeEntry>> lists;

		public static TradeBook Empty { get; } = new TradeBook(new Dictionary<string, List<TradeEntry>>(StringComparer.OrdinalIgnoreCase));

		public long Revision { get; }

		public IReadOnlyList<string> Traders => (from key in lists.Keys
			select key.Substring(0, key.LastIndexOf('.')) into trader
			where !TraderNames.IsCommon(trader)
			select trader).Distinct<string>(StringComparer.OrdinalIgnoreCase).OrderBy<string, string>((string trader) => trader, StringComparer.Ordinal).ToList();

		private TradeBook(Dictionary<string, List<TradeEntry>> lists)
		{
			this.lists = lists;
			Revision = ComputeRevision(lists);
		}

		public static TradeBook Build(IEnumerable<ListContribution> files)
		{
			Dictionary<string, List<TradeEntry>> dictionary = new Dictionary<string, List<TradeEntry>>(StringComparer.OrdinalIgnoreCase);
			foreach (ListContribution item in files.OrderBy((ListContribution file) => (!file.Embedded) ? 1 : 0).ThenBy<ListContribution, string>((ListContribution file) => file.SourceName, StringComparer.OrdinalIgnoreCase).ThenBy<ListContribution, string>((ListContribution file) => file.SourceName, StringComparer.Ordinal))
			{
				string listKey = item.Name.ListKey;
				if (!dictionary.TryGetValue(listKey, out var value))
				{
					value = new List<TradeEntry>();
					dictionary.Add(listKey, value);
				}
				value.AddRange(item.Entries.Select((TradeEntry entry) => entry.Clone()));
			}
			return new TradeBook(dictionary);
		}

		public TradeBook WithAutomatic(IEnumerable<TradeEntry> automatic)
		{
			Dictionary<string, List<TradeEntry>> dictionary = lists.ToDictionary<KeyValuePair<string, List<TradeEntry>>, string, List<TradeEntry>>((KeyValuePair<string, List<TradeEntry>> pair) => pair.Key, (KeyValuePair<string, List<TradeEntry>> pair) => pair.Value.Select((TradeEntry entry) => entry.Clone()).ToList(), StringComparer.OrdinalIgnoreCase);
			string key = TraderNames.CommonKey(ListKind.Sell);
			if (!dictionary.TryGetValue(key, out var value))
			{
				value = new List<TradeEntry>();
				dictionary.Add(key, value);
			}
			value.AddRange(automatic.Select(delegate(TradeEntry entry)
			{
				TradeEntry tradeEntry = entry.Clone();
				tradeEntry.Automatic = true;
				return tradeEntry;
			}));
			return new TradeBook(dictionary);
		}

		public IReadOnlyList<TradeEntry> Buy(string? trader)
		{
			return Combined(trader, ListKind.Buy, includeAutomatic: true);
		}

		public IReadOnlyList<TradeEntry> Sell(string? trader, bool includeAutomatic = true)
		{
			return Combined(trader, ListKind.Sell, includeAutomatic);
		}

		private IReadOnlyList<TradeEntry> Combined(string? trader, ListKind kind, bool includeAutomatic)
		{
			List<TradeEntry> list = new List<TradeEntry>();
			if (lists.TryGetValue(TraderNames.CommonKey(kind), out List<TradeEntry> value))
			{
				list.AddRange(value.Where((TradeEntry entry) => includeAutomatic || !entry.Automatic));
			}
			if (!TraderNames.IsCommon(trader) && lists.TryGetValue(TraderNames.ListKey(trader, kind), out List<TradeEntry> value2))
			{
				list.AddRange(value2.Where((TradeEntry entry) => includeAutomatic || !entry.Automatic));
			}
			if (list.Count != 0)
			{
				return list;
			}
			return None;
		}

		private static long ComputeRevision(Dictionary<string, List<TradeEntry>> lists)
		{
			ulong hash = 14695981039346656037uL;
			foreach (string item in lists.Keys.OrderBy<string, string>((string k) => k, StringComparer.OrdinalIgnoreCase))
			{
				Mix(item.ToLowerInvariant());
				foreach (TradeEntry item2 in lists[item])
				{
					Mix(item2.Prefab);
					Mix(item2.Stack.ToString());
					Mix(item2.Price.ToString());
					Mix(item2.Quality.ToString());
					Mix(item2.Currency);
					Mix(item2.RequiredGlobalKey);
					Mix(item2.NotRequiredGlobalKey);
					Mix(item2.RequiredPlayerKey);
					Mix(item2.NotRequiredPlayerKey);
					Mix(item2.Automatic ? "1" : "0");
				}
			}
			return (long)hash;
			void Mix(string text)
			{
				foreach (char c in text)
				{
					hash ^= c;
					hash *= 1099511628211uL;
				}
				hash ^= 31uL;
				hash *= 1099511628211uL;
			}
		}
	}
	public static class CommonValuables
	{
		public static List<TradeEntry> Build(IEnumerable<(string Prefab, int Value)> items, IEnumerable<string> alreadyListed, string currencyPrefab)
		{
			HashSet<string> hashSet = new HashSet<string>(alreadyListed ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
			List<TradeEntry> list = new List<TradeEntry>();
			foreach (var (text, num) in items)
			{
				if (!string.IsNullOrWhiteSpace(text) && num > 0 && !string.Equals(text, "Coins", StringComparison.OrdinalIgnoreCase) && !string.Equals(text, currencyPrefab, StringComparison.OrdinalIgnoreCase) && hashSet.Add(text))
				{
					list.Add(new TradeEntry
					{
						Prefab = text,
						Price = num,
						Stack = 1,
						Automatic = true
					});
				}
			}
			return list;
		}
	}
	public sealed class TradeEntry
	{
		public string Prefab { get; set; } = string.Empty;

		public int Stack { get; set; } = 1;

		public int Price { get; set; } = 1;

		public int Quality { get; set; }

		public string Currency { get; set; } = string.Empty;

		public string RequiredGlobalKey { get; set; } = string.Empty;

		public string NotRequiredGlobalKey { get; set; } = string.Empty;

		public string RequiredPlayerKey { get; set; } = string.Empty;

		public string NotRequiredPlayerKey { get; set; } = string.Empty;

		public bool Automatic { get; set; }

		public IReadOnlyList<string> Validate()
		{
			List<string> list = new List<string>();
			if (string.IsNullOrWhiteSpace(Prefab))
			{
				list.Add("prefab is empty");
			}
			int encoded;
			if (Price <= 0)
			{
				encoded = Price;
				list.Add("price must be above 0, found " + encoded);
			}
			if (Stack <= 0 || Stack >= 1000000)
			{
				string text = 999999.ToString();
				encoded = Stack;
				list.Add("stack must be from 1 to " + text + ", found " + encoded);
			}
			if (Quality < 0)
			{
				list.Add("quality must not be negative, found " + Quality);
			}
			else if (Stack > 0 && Stack < 1000000 && !TradeAmounts.TryEncodeStack(Stack, Quality, out encoded))
			{
				list.Add("quality " + Quality + " is too large to combine with stack " + Stack);
			}
			return list;
		}

		public static IReadOnlyList<string> SplitKeys(string? value)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrWhiteSpace(value))
			{
				return list;
			}
			string[] array = value.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					list.Add(text);
				}
			}
			return list;
		}

		public TradeEntry Clone()
		{
			return new TradeEntry
			{
				Prefab = Prefab,
				Stack = Stack,
				Price = Price,
				Quality = Quality,
				Currency = Currency,
				RequiredGlobalKey = RequiredGlobalKey,
				NotRequiredGlobalKey = NotRequiredGlobalKey,
				RequiredPlayerKey = RequiredPlayerKey,
				NotRequiredPlayerKey = NotRequiredPlayerKey,
				Automatic = Automatic
			};
		}
	}
	public sealed class ListReadResult
	{
		public List<TradeEntry> Entries { get; } = new List<TradeEntry>();

		public List<string> Errors { get; } = new List<string>();

		public List<string> Warnings { get; } = new List<string>();

		public bool Ok => Errors.Count == 0;
	}
	public static class TradeListReader
	{
		private static readonly string[] Fields = new string[9] { "prefab", "stack", "price", "quality", "currency", "requiredGlobalKey", "notRequiredGlobalKey", "requiredPlayerKey", "notRequiredPlayerKey" };

		public static ListReadResult FromRows(IEnumerable<IReadOnlyDictionary<string, string>>? rows, string source)
		{
			ListReadResult listReadResult = new ListReadResult();
			if (rows == null)
			{
				return listReadResult;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			int num = 0;
			foreach (IReadOnlyDictionary<string, string> row in rows)
			{
				num++;
				Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
				foreach (KeyValuePair<string, string> item in row)
				{
					if (item.Key == null)
					{
						continue;
					}
					if (!Fields.Contains<string>(item.Key, StringComparer.OrdinalIgnoreCase))
					{
						if (hashSet.Add(item.Key))
						{
							listReadResult.Warnings.Add("Ignored unknown field '" + item.Key + "' in '" + source + "'.");
						}
					}
					else
					{
						dictionary[item.Key] = item.Value ?? string.Empty;
					}
				}
				TradeEntry tradeEntry = new TradeEntry();
				try
				{
					tradeEntry.Prefab = Text(dictionary, "prefab");
					tradeEntry.Stack = Number(dictionary, "stack", tradeEntry.Stack, source, num);
					tradeEntry.Price = Number(dictionary, "price", tradeEntry.Price, source, num);
					tradeEntry.Quality = Number(dictionary, "quality", tradeEntry.Quality, source, num);
				}
				catch (FormatException ex)
				{
					listReadResult.Errors.Add(ex.Message);
					continue;
				}
				tradeEntry.Currency = Text(dictionary, "currency");
				tradeEntry.RequiredGlobalKey = Text(dictionary, "requiredGlobalKey");
				tradeEntry.NotRequiredGlobalKey = Text(dictionary, "notRequiredGlobalKey");
				tradeEntry.RequiredPlayerKey = Text(dictionary, "requiredPlayerKey");
				tradeEntry.NotRequiredPlayerKey = Text(dictionary, "notRequiredPlayerKey");
				if (string.IsNullOrWhiteSpace(tradeEntry.Prefab))
				{
					listReadResult.Warnings.Add($"Skipped row {num} of '{source}': it has no prefab.");
					continue;
				}
				IReadOnlyList<string> readOnlyList = tradeEntry.Validate();
				if (readOnlyList.Count > 0)
				{
					listReadResult.Warnings.Add(string.Format("Skipped row {0} of '{1}' ({2}): {3}.", num, source, tradeEntry.Prefab, string.Join("; ", readOnlyList)));
				}
				else
				{
					listReadResult.Entries.Add(tradeEntry);
				}
			}
			return listReadResult;
		}

		public static ListReadResult FromCsv(string? content, string source)
		{
			try
			{
				List<List<string>> list = ParseCsvRecords(content ?? string.Empty);
				if (list.Count == 0)
				{
					return new ListReadResult();
				}
				string[] array = list[0].Select((string header, int index) => (index != 0) ? (header ?? string.Empty).Trim() : (header ?? string.Empty).TrimStart('\ufeff').Trim()).ToArray();
				if (!array.Any((string header) => string.Equals(header, "prefab", StringComparison.OrdinalIgnoreCase)))
				{
					throw new FormatException("CSV list '" + source + "' must contain the 'prefab' header.");
				}
				if (array.Where((string header) => header.Length > 0).GroupBy<string, string>((string header) => header, StringComparer.OrdinalIgnoreCase).Any((IGrouping<string, string> group) => group.Count() > 1))
				{
					throw new FormatException("CSV list '" + source + "' contains a duplicate column header.");
				}
				List<IReadOnlyDictionary<string, string>> list2 = new List<IReadOnlyDictionary<string, string>>();
				for (int num = 1; num < list.Count; num++)
				{
					List<string> list3 = list[num];
					if (list3.All(string.IsNullOrWhiteSpace))
					{
						continue;
					}
					if (list3.Skip(array.Length).Any((string value2) => !string.IsNullOrWhiteSpace(value2)))
					{
						throw new FormatException($"CSV row {num + 1} of '{source}' has more values than its header.");
					}
					Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
					for (int num2 = 0; num2 < array.Length; num2++)
					{
						if (array[num2].Length != 0)
						{
							string value = ((num2 < list3.Count) ? (list3[num2] ?? string.Empty) : string.Empty);
							dictionary[array[num2]] = value;
						}
					}
					list2.Add(dictionary);
				}
				return FromRows(list2, source);
			}
			catch (FormatException ex)
			{
				return new ListReadResult
				{
					Errors = { ex.Message }
				};
			}
		}

		private static string Text(Dictionary<string, string> row, string field)
		{
			if (!row.TryGetValue(field, out string value))
			{
				return string.Empty;
			}
			return (value ?? string.Empty).Trim();
		}

		private static int Number(Dictionary<string, string> row, string field, int fallback, string source, int rowNumber)
		{
			string text = Text(row, field);
			if (text.Length == 0)
			{
				return fallback;
			}
			if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			throw new FormatException($"Invalid integer '{text}' in row {rowNumber}, field '{field}' of '{source}'.");
		}

		internal static List<List<string>> ParseCsvRecords(string content)
		{
			List<List<string>> list = new List<List<string>>();
			List<string> list2 = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = false;
			bool flag2 = false;
			content = (content ?? string.Empty).TrimStart('\ufeff');
			for (int i = 0; i < content.Length; i++)
			{
				char c = content[i];
				if (flag)
				{
					if (c != '"')
					{
						stringBuilder.Append(c);
					}
					else if (i + 1 < content.Length && content[i + 1] == '"')
					{
						stringBuilder.Append('"');
						i++;
					}
					else
					{
						flag = false;
						flag2 = true;
					}
					continue;
				}
				switch (c)
				{
				case '\n':
				case '\r':
				case ',':
					list2.Add(stringBuilder.ToString());
					stringBuilder.Clear();
					flag2 = false;
					if (c != ',')
					{
						if (c == '\r' && i + 1 < content.Length && content[i + 1] == '\n')
						{
							i++;
						}
						list.Add(list2);
						list2 = new List<string>();
					}
					continue;
				case '"':
					if (stringBuilder.Length == 0 && !flag2)
					{
						flag = true;
						continue;
					}
					break;
				}
				if (flag2 || c == '"')
				{
					throw new FormatException("CSV contains unexpected text outside a quoted field.");
				}
				stringBuilder.Append(c);
			}
			if (flag)
			{
				throw new FormatException("CSV contains an unterminated quote in a quoted field.");
			}
			if (stringBuilder.Length > 0 || flag2 || list2.Count > 0)
			{
				list2.Add(stringBuilder.ToString());
				list.Add(list2);
			}
			return list;
		}
	}
	public static class TraderNames
	{
		public static readonly IReadOnlyList<string> Vanilla = new string[3] { "Haldor", "Hildir", "BogWitch" };

		public static string Normalize(string? name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return string.Empty;
			}
			return name.Trim().ToLowerInvariant().Replace("$npc_", string.Empty)
				.Replace("npc_", string.Empty);
		}

		public static string ListKey(string? trader, ListKind kind)
		{
			return Normalize(trader) + "." + kind;
		}

		public static string CommonKey(ListKind kind)
		{
			return ListKey("common", kind);
		}

		public static bool IsCommon(string? trader)
		{
			return string.Equals(Normalize(trader), "common", StringComparison.Ordinal);
		}

		public static IEnumerable<string> SplitList(string? value)
		{
			string[] array = (value ?? string.Empty).Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					yield return text;
				}
			}
		}

		public static bool ListContains(string? value, string? trader)
		{
			string b = Normalize(trader);
			foreach (string item in SplitList(value))
			{
				if (string.Equals(Normalize(item), b, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace ExtraPotions.Barter.Currency
{
	public static class CurrencyRules
	{
		public static string ForTrader(string? overrides, string? trader, out string? warning)
		{
			warning = null;
			if (string.IsNullOrWhiteSpace(overrides))
			{
				return string.Empty;
			}
			string text = overrides.Trim();
			if (text.IndexOf(':') < 0 && text.IndexOf('=') < 0 && text.IndexOf(',') < 0 && text.IndexOf(';') < 0 && text.IndexOf('\n') < 0 && text.IndexOf('\r') < 0)
			{
				warning = "Ignored invalid trader currency override '" + text + "'. Expected TraderPrefab:CurrencyPrefab.";
				return string.Empty;
			}
			string b = TraderNames.Normalize(trader);
			string[] array = text.Split(new char[4] { ',', ';', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				int num = text2.IndexOf(':');
				if (num < 0)
				{
					num = text2.IndexOf('=');
				}
				if (num > 0 && num < text2.Length - 1 && string.Equals(TraderNames.Normalize(text2.Substring(0, num)), b, StringComparison.OrdinalIgnoreCase))
				{
					return text2.Substring(num + 1).Trim();
				}
			}
			return string.Empty;
		}

		public static string Effective(string? entryCurrency, string? traderCurrency)
		{
			string text = (entryCurrency ?? string.Empty).Trim();
			if (text.Length <= 0)
			{
				return (traderCurrency ?? string.Empty).Trim();
			}
			return text;
		}

		public static bool IsVanilla(string? currency)
		{
			if (!string.IsNullOrWhiteSpace(currency))
			{
				return string.Equals(currency.Trim(), "Coins", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		public static string PrefabOrVanilla(string? currency)
		{
			if (!string.IsNullOrWhiteSpace(currency))
			{
				return currency.Trim();
			}
			return "Coins";
		}
	}
}
namespace ExtraPotions.Barter.Config
{
	public enum SettingScope
	{
		Local,
		ServerAuthoritative
	}
	public abstract class BarterSetting
	{
		public string Section { get; }

		public string Key { get; }

		public string Id => Section + "." + Key;

		public SettingScope Scope { get; }

		public string Description { get; }

		public abstract Type ValueType { get; }

		public abstract object DefaultValue { get; }

		public abstract object? Minimum { get; }

		public abstract object? Maximum { get; }

		private protected BarterSetting(string section, string key, SettingScope scope, string description)
		{
			if (string.IsNullOrWhiteSpace(section) || section.Trim() != section)
			{
				throw new ArgumentException("Expected a trimmed section name.", "section");
			}
			if (string.IsNullOrWhiteSpace(key) || key.Trim() != key)
			{
				throw new ArgumentException("Expected a trimmed key.", "key");
			}
			if (!Enum.IsDefined(typeof(SettingScope), scope))
			{
				throw new ArgumentException("Unknown scope.", "scope");
			}
			if (string.IsNullOrWhiteSpace(description))
			{
				throw new ArgumentException("Expected a description.", "description");
			}
			Section = section;
			Key = key;
			Scope = scope;
			Description = description;
		}

		public abstract object NormalizeBoxed(object? value);

		public override string ToString()
		{
			return Id + " (" + Scope.ToString() + ")";
		}

		public static BarterSetting<bool> Toggle(string section, string key, bool defaultValue, SettingScope scope, string description)
		{
			return new BarterSetting<bool>(section, key, scope, description, defaultValue, null, (bool v) => v);
		}

		public static BarterSetting<int> Integer(string section, string key, int defaultValue, int min, int max, SettingScope scope, string description)
		{
			if (min > max)
			{
				throw new ArgumentException("Minimum above maximum.", "min");
			}
			return new BarterSetting<int>(section, key, scope, description, defaultValue, (min, max), (int v) => Math.Min(max, Math.Max(min, v)));
		}

		public static BarterSetting<float> Number(string section, string key, float defaultValue, float min, float max, SettingScope scope, string description)
		{
			if (!(min <= max) || float.IsInfinity(min) || float.IsInfinity(max))
			{
				throw new ArgumentException("Expected a finite range.", "min");
			}
			return new BarterSetting<float>(section, key, scope, description, defaultValue, (min, max), (float v) => (!float.IsNaN(v) && !float.IsInfinity(v)) ? Math.Min(max, Math.Max(min, v)) : defaultValue);
		}

		public static BarterSetting<string> Text(string section, string key, string defaultValue, SettingScope scope, string description, Func<string, string> normalize)
		{
			if (normalize == null)
			{
				throw new ArgumentNullException("normalize");
			}
			return new BarterSetting<string>(section, key, scope, description, defaultValue, null, normalize);
		}
	}
	public sealed class BarterSetting<T> : BarterSetting
	{
		private readonly Func<T, T> normalize;

		private readonly (T Min, T Max)? range;

		public T Default { get; }

		public override Type ValueType => typeof(T);

		public override object DefaultValue => Default;

		public override object? Minimum
		{
			get
			{
				if (!range.HasValue)
				{
					return null;
				}
				return range.Value.Min;
			}
		}

		public override object? Maximum
		{
			get
			{
				if (!range.HasValue)
				{
					return null;
				}
				return range.Value.Max;
			}
		}

		internal BarterSetting(string section, string key, SettingScope scope, string description, T defaultValue, (T, T)? range, Func<T, T> normalize)
			: base(section, key, scope, description)
		{
			this.normalize = normalize ?? throw new ArgumentNullException("normalize");
			this.range = range;
			if (!EqualityComparer<T>.Default.Equals(normalize(defaultValue), defaultValue))
			{
				throw new ArgumentException(base.Id + ": the default is outside its own rule.", "defaultValue");
			}
			Default = defaultValue;
		}

		public T Normalize(T value)
		{
			return normalize(value);
		}

		public override object NormalizeBoxed(object? value)
		{
			return (value is T value2) ? Normalize(value2) : Default;
		}
	}
	public static class BarterSettings
	{
		public static class Purse
		{
			public const string Section = "Trader Purse";

			public static readonly BarterSetting<bool> Enabled = BarterSetting.Toggle("Trader Purse", "Enabled", defaultValue: true, SettingScope.ServerAuthoritative, "Traders that have a Barter list (Haldor, Hildir and the Bog Witch with the shipped lists, Custom Traders, and any trader you write a list for) have a limited balance that goes down when they pay you and up when you buy, and refills each morning. Other mods' traders keep the game's prices.");

			public static readonly BarterSetting<bool> FlexiblePricing = BarterSetting.Toggle("Trader Purse", "Flexible Pricing", defaultValue: true, SettingScope.ServerAuthoritative, "Prices follow the trader's balance: a poor trader charges more and pays less, a rich one the opposite.");

			public static readonly BarterSetting<int> MinimumBalance = BarterSetting.Integer("Trader Purse", "Minimum Balance", 2000, 0, 1000000, SettingScope.ServerAuthoritative, "The balance a trader starts with and never refills below; prices are neutral at this balance.");

			public static readonly BarterSetting<int> MaximumBalance = BarterSetting.Integer("Trader Purse", "Maximum Balance", 6000, 0, 1000000, SettingScope.ServerAuthoritative, "The balance a trader refills up to; prices reach the discount and the markup at this balance.");

			public static readonly BarterSetting<int> DailyIncrease = BarterSetting.Integer("Trader Purse", "Daily Increase", 1000, 0, 1000000, SettingScope.ServerAuthoritative, "How much a trader's balance grows at each refill, up to the maximum.");

			public static readonly BarterSetting<int> DailyDecrease = BarterSetting.Integer("Trader Purse", "Daily Decrease", 0, 0, 1000000, SettingScope.ServerAuthoritative, "How much a balance above the maximum shrinks at each refill, down to the maximum.");

			public static readonly BarterSetting<float> Discount = BarterSetting.Number("Trader Purse", "Discount", 0.7f, 0f, 10f, SettingScope.ServerAuthoritative, "The price you pay at the maximum balance, as a factor (0.7 is 30 percent off); also what an empty purse pays you.");

			public static readonly BarterSetting<float> Markup = BarterSetting.Number("Trader Purse", "Markup", 1.5f, 0f, 10f, SettingScope.ServerAuthoritative, "The price you pay at an empty purse, as a factor (1.5 is 50 percent more); also what a full purse pays you.");

			public static readonly BarterSetting<int> ReplenishDays = BarterSetting.Integer("Trader Purse", "Replenish Days", 1, 1, 365, SettingScope.ServerAuthoritative, "How many in-game days pass between refills of a trader's balance.");

			public static readonly BarterSetting<bool> ReplenishMessage = BarterSetting.Toggle("Trader Purse", "Replenish Message", defaultValue: true, SettingScope.ServerAuthoritative, "Tell everyone in the morning when trader balances were refilled.");
		}

		public static class Lists
		{
			public const string Section = "Trade Lists";

			public static readonly BarterSetting<bool> SellOnlyDiscovered = BarterSetting.Toggle("Trade Lists", "Sell Only Discovered", defaultValue: true, SettingScope.ServerAuthoritative, "A trader does not offer items you have not discovered yet.");

			public static readonly BarterSetting<string> AlwaysOffered = BarterSetting.Text("Trade Lists", "Always Offered", "", SettingScope.ServerAuthoritative, "Comma list of item prefabs a trader offers even when you have not discovered them. Items the game's own traders sell are always included.", Trim);

			public static readonly BarterSetting<bool> DisableVanillaItems = BarterSetting.Toggle("Trade Lists", "Disable Vanilla Items", defaultValue: false, SettingScope.ServerAuthoritative, "Remove the game's own items from trader buy lists, so only Barter's lists remain. Progress purchases such as inventory rows stay.");

			public static readonly BarterSetting<bool> DisableOtherModsItems = BarterSetting.Toggle("Trade Lists", "Disable Other Mods Items", defaultValue: false, SettingScope.ServerAuthoritative, "Remove items other mods added to trader buy lists before Barter adds its own.");

			public static readonly BarterSetting<float> QualityPriceMultiplier = BarterSetting.Number("Trade Lists", "Quality Price Multiplier", 0f, 0f, 10f, SettingScope.ServerAuthoritative, "Extra price per quality level above one when you sell gear, as a share of the listed price (0.5 adds half per level). 0 ignores quality.");

			public static readonly BarterSetting<bool> CommonValuables = BarterSetting.Toggle("Trade Lists", "Common Valuables", defaultValue: true, SettingScope.ServerAuthoritative, "Every item the game gives a value can be sold to any trader at that value, unless a Sell list prices it.");

			public static readonly BarterSetting<string> CustomTraders = BarterSetting.Text("Trade Lists", "Custom Traders", "", SettingScope.ServerAuthoritative, "Comma list of extra trader prefab names (case sensitive in the game) that get a balance and use Barter's lists.", Trim);

			public static readonly BarterSetting<string> TraderCurrencies = BarterSetting.Text("Trade Lists", "Trader Currencies", "", SettingScope.ServerAuthoritative, "Comma list of Trader:Currency pairs, for example Haldor:Coins,Hildir:SilverCoin. The item is that trader's currency unless a list entry names its own.", Trim);
		}

		public static class Services
		{
			public const string Section = "Trader Services";

			public static readonly BarterSetting<bool> BuybackEnabled = BarterSetting.Toggle("Trader Services", "Buyback Enabled", defaultValue: true, SettingScope.ServerAuthoritative, "Keep exact sold items available to their seller until the next in-game day. The server owns receipts; buying back costs the original payout.");

			public static readonly BarterSetting<bool> RepairEnabled = BarterSetting.Toggle("Trader Services", "Repair Enabled", defaultValue: true, SettingScope.ServerAuthoritative, "Let traders repair carried equipment for their own currency. The server owns eligibility and prices.");

			public static readonly BarterSetting<int> RepairBasePrice = BarterSetting.Integer("Trader Services", "Repair Base Price", 10, 1, 1000000, SettingScope.ServerAuthoritative, "Base price for repairing a fully damaged quality-one item; scales with quality, missing durability and the trader's buy price.");
		}

		public static class Interface
		{
			public const string Section = "Interface";

			public static readonly BarterSetting<bool> PriceTips = BarterSetting.Toggle("Interface", "Price Tips", defaultValue: true, SettingScope.Local, "Append this trader's current effective buy and sell prices to item tooltips while trading. Prices are quotes and may change before a trade.");

			public static readonly BarterSetting<bool> SellPanel = BarterSetting.Toggle("Interface", "Sell Panel", defaultValue: true, SettingScope.Local, "Show the sell list beside the trader's window.");

			public static readonly BarterSetting<bool> ShowPurse = BarterSetting.Toggle("Interface", "Show Purse", defaultValue: true, SettingScope.Local, "Show the trader's balance, currency and price change beside the trader's window.");

			public static readonly BarterSetting<bool> HideEquipped = BarterSetting.Toggle("Interface", "Hide Equipped Items", defaultValue: true, SettingScope.Local, "Leave unequipped hotbar gear out of the sell list. Equipped gear and protected extra slots are always kept.");
		}

		private static readonly Lazy<BarterSetting[]> all = new Lazy<BarterSetting[]>(() => new BarterSetting[25]
		{
			Purse.Enabled,
			Purse.FlexiblePricing,
			Purse.MinimumBalance,
			Purse.MaximumBalance,
			Purse.DailyIncrease,
			Purse.DailyDecrease,
			Purse.Discount,
			Purse.Markup,
			Purse.ReplenishDays,
			Purse.ReplenishMessage,
			Lists.SellOnlyDiscovered,
			Lists.AlwaysOffered,
			Lists.DisableVanillaItems,
			Lists.DisableOtherModsItems,
			Lists.QualityPriceMultiplier,
			Lists.CommonValuables,
			Lists.CustomTraders,
			Lists.TraderCurrencies,
			Services.BuybackEnabled,
			Services.RepairEnabled,
			Services.RepairBasePrice,
			Interface.PriceTips,
			Interface.SellPanel,
			Interface.ShowPurse,
			Interface.HideEquipped
		});

		private static readonly Lazy<Dictionary<string, BarterSetting>> byId = new Lazy<Dictionary<string, BarterSetting>>(() => all.Value.ToDictionary<BarterSetting, string>((BarterSetting s) => s.Id, StringComparer.OrdinalIgnoreCase));

		public static IReadOnlyList<BarterSetting> All => all.Value;

		public static BarterSetting? Find(string? id)
		{
			if (id == null || !byId.Value.TryGetValue(id.Trim(), out BarterSetting value

plugins/Barter/Barter.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExtraPotions.Barter.Availability;
using ExtraPotions.Barter.Config;
using ExtraPotions.Barter.Currency;
using ExtraPotions.Barter.Lists;
using ExtraPotions.Barter.Pricing;
using ExtraPotions.Barter.Runtime.Lists;
using ExtraPotions.Barter.Trading;
using ExtraPotions.Meadworks.Crucible;
using ExtraPotions.Meadworks.Crucible.UI;
using GUIFramework;
using HarmonyLib;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: AssemblyInformationalVersion("0.1.4")]
[assembly: AssemblyProduct("Barter")]
[assembly: AssemblyTitle("Barter")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 ExtraPotions.Barter.Runtime
{
	public static class BarterText
	{
		private static MeadworksTranslations catalog;

		public static void Initialize(BepInPlugin metadata, ManualLogSource log)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			Assembly assembly = typeof(BarterText).Assembly;
			foreach (string item in MeadworksLanguages.Supported)
			{
				using Stream stream = assembly.GetManifestResourceStream("Barter.localization." + item + ".json");
				if (stream != null)
				{
					using StreamReader streamReader = new StreamReader(stream);
					dictionary.Add(item, streamReader.ReadToEnd());
				}
			}
			catalog = MeadworksTranslations.Register(metadata, new ProductTranslations("barter", (IReadOnlyDictionary<string, string>)dictionary), (string)null, log);
		}

		public static string Text(string key)
		{
			MeadworksTranslations obj = catalog;
			return ((obj != null) ? obj.Text(key) : null) ?? key;
		}

		public static string Format(string key, params object[] arguments)
		{
			MeadworksTranslations obj = catalog;
			return ((obj != null) ? obj.Format(key, arguments) : null) ?? key;
		}

		public static string Token(string key)
		{
			MeadworksTranslations obj = catalog;
			return "$" + (((obj != null) ? obj.Token(key) : null) ?? ("meadworks_barter_" + key));
		}

		public static void Tick()
		{
			MeadworksTranslations obj = catalog;
			if (obj != null)
			{
				obj.Update();
			}
		}

		public static void Shutdown()
		{
			MeadworksTranslations obj = catalog;
			if (obj != null)
			{
				obj.Dispose();
			}
			catalog = null;
		}
	}
	public sealed class BarterConfig
	{
		private const string Product = "com.meadworks.barter";

		private readonly ConfigFile file;

		private readonly Dictionary<BarterSetting, ConfigEntryBase> entries = new Dictionary<BarterSetting, ConfigEntryBase>();

		public event EventHandler Changed;

		private BarterConfig(ConfigFile file)
		{
			this.file = file;
			bool saveOnConfigSet = file.SaveOnConfigSet;
			file.SaveOnConfigSet = false;
			try
			{
				foreach (BarterSetting item in BarterSettings.All)
				{
					BindSetting(item);
				}
			}
			finally
			{
				file.SaveOnConfigSet = saveOnConfigSet;
			}
			file.Save();
			file.SettingChanged += OnSettingChanged;
		}

		public static BarterConfig Bind(ConfigFile file, MeadworksLog log)
		{
			if (file == null)
			{
				throw new ArgumentNullException("file");
			}
			BarterConfig barterConfig = new BarterConfig(file);
			foreach (KeyValuePair<BarterSetting, ConfigEntryBase> item in barterConfig.entries.Where<KeyValuePair<BarterSetting, ConfigEntryBase>>((KeyValuePair<BarterSetting, ConfigEntryBase> p) => (int)p.Key.Scope > 0))
			{
				MeadworksBlockedOptions.Track("com.meadworks.barter", item.Value, (ConfigScope)1, true);
			}
			if (log != null)
			{
				log.Verbose("Configuration bound: " + barterConfig.entries.Count<KeyValuePair<BarterSetting, ConfigEntryBase>>((KeyValuePair<BarterSetting, ConfigEntryBase> p) => (int)p.Key.Scope == 0) + " Local, " + barterConfig.entries.Count<KeyValuePair<BarterSetting, ConfigEntryBase>>((KeyValuePair<BarterSetting, ConfigEntryBase> p) => (int)p.Key.Scope == 1) + " ServerAuthoritative.");
			}
			return barterConfig;
		}

		public ConfigEntryBase Entry(BarterSetting setting)
		{
			if (!entries.TryGetValue(setting ?? throw new ArgumentNullException("setting"), out ConfigEntryBase value))
			{
				throw new ArgumentException("Not a Barter setting.", "setting");
			}
			return value;
		}

		public T Get<T>(BarterSetting<T> setting)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			ConfigEntry<T> val = (ConfigEntry<T>)(object)Entry((BarterSetting)(object)setting);
			if ((int)((BarterSetting)setting).Scope != 1)
			{
				return setting.Normalize(val.Value);
			}
			return setting.Normalize(MeadworksConfig.Effective<T>(val, "com.meadworks.barter", (ConfigScope)1, setting.Default, true));
		}

		public T GetFor<T>(BarterSetting<T> setting, string trader)
		{
			return TraderPolicies.Get(setting, trader, Get<T>(setting));
		}

		public PurseRules Purse()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			return new PurseRules
			{
				Enabled = Get<bool>(Purse.Enabled),
				Flexible = Get<bool>(Purse.FlexiblePricing),
				Minimum = Get<int>(Purse.MinimumBalance),
				Maximum = Get<int>(Purse.MaximumBalance),
				DailyIncrease = Get<int>(Purse.DailyIncrease),
				DailyDecrease = Get<int>(Purse.DailyDecrease),
				Discount = Get<float>(Purse.Discount),
				Markup = Get<float>(Purse.Markup),
				ReplenishDays = Get<int>(Purse.ReplenishDays)
			};
		}

		public void Shutdown()
		{
			file.SettingChanged -= OnSettingChanged;
			this.Changed = null;
			foreach (ConfigEntryBase value in entries.Values)
			{
				MeadworksBlockedOptions.Untrack(value);
			}
		}

		private void OnSettingChanged(object sender, SettingChangedEventArgs args)
		{
			this.Changed?.Invoke(this, EventArgs.Empty);
		}

		private void BindSetting(BarterSetting setting)
		{
			ConfigEntryBase value;
			if (!(setting is BarterSetting<bool> setting2))
			{
				if (!(setting is BarterSetting<int> val))
				{
					if (!(setting is BarterSetting<float> val2))
					{
						if (!(setting is BarterSetting<string> setting3))
						{
							throw new NotSupportedException(setting.Id + ": unsupported value type " + setting.ValueType.Name + ".");
						}
						value = (ConfigEntryBase)(object)Bind<string>(setting3, null);
					}
					else
					{
						value = (ConfigEntryBase)(object)Bind<float>(val2, (AcceptableValueBase)(object)new AcceptableValueRange<float>((float)((BarterSetting)val2).Minimum, (float)((BarterSetting)val2).Maximum));
					}
				}
				else
				{
					value = (ConfigEntryBase)(object)Bind<int>(val, (AcceptableValueBase)(object)new AcceptableValueRange<int>((int)((BarterSetting)val).Minimum, (int)((BarterSetting)val).Maximum));
				}
			}
			else
			{
				value = (ConfigEntryBase)(object)Bind<bool>(setting2, null);
			}
			entries.Add(setting, value);
		}

		private ConfigEntry<T> Bind<T>(BarterSetting<T> setting, AcceptableValueBase acceptable)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			return MeadworksConfig.Bind<T>(file, ((BarterSetting)setting).Section, ((BarterSetting)setting).Key, setting.Default, ((BarterSetting)setting).Description, (ConfigScope)(((int)((BarterSetting)setting).Scope != 0) ? 1 : 0), acceptable);
		}
	}
	internal sealed class SyncReceipt
	{
		private ZNet network;

		private ZRpc server;

		private string epoch = "";

		private long world;

		internal long CurrentGeneration
		{
			get
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Invalid comparison between Unknown and I4
				if (!Plugin.IsReady || (Object)(object)network == (Object)null || server == null || !server.IsConnected() || network != ZNet.instance || network.IsServer() || server != network.GetServerRPC())
				{
					return -1L;
				}
				SessionSnapshot session = Plugin.Session;
				if ((int)session.Role != 3 || !session.AuthorityReady || session.WorldId == 0L || string.IsNullOrEmpty(session.SessionId))
				{
					return -1L;
				}
				if (epoch.Length == 0)
				{
					epoch = session.SessionId;
					world = session.WorldId;
				}
				if (!(epoch == session.SessionId) || world != session.WorldId)
				{
					return -1L;
				}
				return session.Generation;
			}
		}

		internal void Observe()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			network = ZNet.instance;
			server = (((Object)(object)network != (Object)null && !network.IsServer()) ? network.GetServerRPC() : null);
			epoch = "";
			world = 0L;
			if (server != null && server.IsConnected() && Plugin.IsReady)
			{
				SessionSnapshot session = Plugin.Session;
				if ((int)session.Role == 3 && !string.IsNullOrEmpty(session.SessionId))
				{
					epoch = session.SessionId;
					world = session.WorldId;
				}
			}
		}
	}
	internal static class TraderPolicies
	{
		internal const string FileName = "Barter.Traders.json";

		private const string Empty = "{\"version\":1,\"traders\":{}}";

		private static ConfigEntry<string> carrier;

		private static SyncReceipt receipt = new SyncReceipt();

		private static TraderPolicyBook current = TraderPolicyBook.Empty;

		private static long generation = -1L;

		private static float nextCheck;

		private static string applied;

		private static bool initialized;

		internal static bool Ready { get; private set; }

		internal static event Action Changed;

		internal static void Initialize(ConfigFile config)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			try
			{
				ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
				{
					Browsable = false,
					ReadOnly = true
				};
				carrier = ConfigFileExtensions.BindConfig<string>(config, "Trade Lists", "Managed Trader Policies", "", "Managed by Barter: server trader policies. Edit Barter.Traders.json on the host.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, val);
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
			config.Save();
			SynchronizationManager.OnConfigurationSynchronized += Synchronized;
			initialized = true;
			Tick();
		}

		private static void Synchronized(object sender, ConfigurationSynchronizationEventArgs args)
		{
			if (Plugin.IsReady && args.UpdatedPluginGUIDs != null && args.UpdatedPluginGUIDs.Contains("com.meadworks.barter"))
			{
				receipt.Observe();
				nextCheck = 0f;
			}
		}

		internal static T Get<T>(BarterSetting<T> setting, string trader, T fallback)
		{
			return current.Get<T>(trader, setting, fallback);
		}

		internal static string Currency(string trader, string fallback)
		{
			return current.Currency(trader, fallback);
		}

		internal static bool HasTrader(string trader)
		{
			return current.Traders.ContainsKey(TraderNames.Normalize(trader));
		}

		internal static void Tick()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Invalid comparison between Unknown and I4
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Invalid comparison between Unknown and I4
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Invalid comparison between Unknown and I4
			if (!initialized || !Plugin.IsReady)
			{
				return;
			}
			if (generation != Plugin.Session.Generation)
			{
				generation = Plugin.Session.Generation;
				applied = null;
				current = TraderPolicyBook.Empty;
				Ready = false;
				nextCheck = 0f;
			}
			if (Time.unscaledTime < nextCheck)
			{
				return;
			}
			nextCheck = Time.unscaledTime + 2f;
			try
			{
				bool flag = (int)Plugin.Session.Role == 3;
				AuthorityDecision val = MeadworksAuthority.Decide("com.meadworks.barter", (ConfigScope)1, true);
				if ((int)val.Source == 2 || (flag && ((int)val.Source != 1 || receipt.CurrentGeneration != generation)))
				{
					current = TraderPolicyBook.Empty;
					Ready = false;
					return;
				}
				string text;
				if (flag)
				{
					text = MeadworksConfig.Effective<string>(carrier, "com.meadworks.barter", (ConfigScope)1, "", true);
				}
				else
				{
					string text2 = Path.Combine(Paths.ConfigPath, "Barter.Traders.json");
					if (!File.Exists(text2))
					{
						text = "{\"version\":1,\"traders\":{}}";
					}
					else
					{
						if (new FileInfo(text2).Length > 262144)
						{
							throw new InvalidDataException("Trader policies exceed 256 KiB.");
						}
						text = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(File.ReadAllBytes(text2)).TrimStart('\ufeff');
					}
				}
				if (!(text == applied) || !Ready)
				{
					current = TraderPolicyJson.Read(text);
					applied = text;
					Ready = true;
					if (!flag && carrier.Value != text)
					{
						MeadworksConfig.Amend<string>(carrier, "com.meadworks.barter", (ConfigScope)1, text, (string)null, true);
					}
					TraderPolicies.Changed?.Invoke();
				}
			}
			catch (Exception ex)
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning("Trader policy reload refused: " + ex.GetType().Name + ": " + ex.Message);
				}
			}
		}

		internal static void Shutdown()
		{
			SynchronizationManager.OnConfigurationSynchronized -= Synchronized;
			initialized = false;
			carrier = null;
			current = TraderPolicyBook.Empty;
			applied = null;
			Ready = false;
			generation = -1L;
			receipt = new SyncReceipt();
			TraderPolicies.Changed = null;
		}
	}
	internal static class TraderPolicyJson
	{
		internal const int MaximumBytes = 262144;

		internal static TraderPolicyBook Read(string text)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Invalid comparison between Unknown and I4
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Expected O, but got Unknown
			if (Encoding.UTF8.GetByteCount(text) > 262144)
			{
				throw new InvalidDataException("Trader policies exceed 256 KiB.");
			}
			JsonTextReader val = new JsonTextReader((TextReader)new StringReader(text))
			{
				DateParseHandling = (DateParseHandling)0,
				MaxDepth = 12
			};
			try
			{
				JObject val2 = JObject.Load((JsonReader)(object)val, new JsonLoadSettings
				{
					DuplicatePropertyNameHandling = (DuplicatePropertyNameHandling)2
				});
				if (((JsonReader)val).Read())
				{
					throw new InvalidDataException("Unexpected content after trader policies.");
				}
				if (val2.Properties().Count() == 2)
				{
					JToken obj = val2["version"];
					if (obj != null && (int)obj.Type == 6 && Extensions.Value<int>((IEnumerable<JToken>)val2["version"]) == 1)
					{
						JToken obj2 = val2["traders"];
						JObject val3 = (JObject)(object)((obj2 is JObject) ? obj2 : null);
						if (val3 != null)
						{
							Dictionary<string, IDictionary<string, object>> dictionary = new Dictionary<string, IDictionary<string, object>>(StringComparer.Ordinal);
							foreach (JProperty item in val3.Properties())
							{
								JToken value = item.Value;
								JToken obj3 = ((value is JObject) ? value : null) ?? throw new InvalidDataException("Expected trader settings object.");
								Dictionary<string, object> dictionary2 = new Dictionary<string, object>(StringComparer.Ordinal);
								foreach (JProperty item2 in ((JObject)obj3).Properties())
								{
									JToken value2 = item2.Value;
									JValue val4 = (JValue)(object)((value2 is JValue) ? value2 : null);
									if (val4 == null || val4.Value == null)
									{
										throw new InvalidDataException("Expected scalar setting values.");
									}
									dictionary2.Add(item2.Name, val4.Value);
								}
								dictionary.Add(item.Name, dictionary2);
							}
							return new TraderPolicyBook((IDictionary<string, IDictionary<string, object>>)dictionary);
						}
					}
				}
				throw new InvalidDataException("Expected version 1 and a traders object.");
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		internal static string Write(TraderPolicyBook book)
		{
			return JsonConvert.SerializeObject((object)new
			{
				version = 1,
				traders = book.Traders
			}, (Formatting)1);
		}
	}
	internal sealed class AuthorityReceipt
	{
		internal string Actor = "";

		internal string Fingerprint = "";

		internal string Epoch = "";

		internal byte State;

		internal bool Applied;

		internal bool CharacterConsumed;

		private static readonly Dictionary<ZDOID, string> rotated = new Dictionary<ZDOID, string>();

		private static string rotationEpoch = "";

		internal static void Rotate(ZDO zdo, PurseLedger ledger, string epoch)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (rotationEpoch != epoch)
			{
				rotated.Clear();
				rotationEpoch = epoch;
			}
			if (rotated.TryGetValue(zdo.m_uid, out string value) && value == epoch)
			{
				return;
			}
			string[] array = AuthorityState.Fields(zdo, "receipt-");
			foreach (string text in array)
			{
				string text2 = text.Substring("receipt-".Length);
				if (!(text2 == ledger.Token))
				{
					AuthorityReceipt authorityReceipt = Read(zdo, text2);
					if (authorityReceipt != null && authorityReceipt.Applied && authorityReceipt.Epoch != epoch)
					{
						AuthorityState.Remove(zdo, text);
					}
				}
			}
			rotated[zdo.m_uid] = epoch;
		}

		internal static void FinalizePrevious(ZDO zdo, PurseLedger ledger)
		{
			if (ledger.Pending || ledger.Token.Length == 0)
			{
				return;
			}
			AuthorityReceipt authorityReceipt = Read(zdo, ledger.Token);
			if (authorityReceipt != null && !authorityReceipt.Applied)
			{
				if (authorityReceipt.Actor != ledger.Actor || authorityReceipt.Fingerprint != ledger.Fingerprint)
				{
					throw new InvalidDataException("Prior settlement receipt mismatch");
				}
				authorityReceipt.State = (byte)(ledger.Quarantined ? 4 : ((authorityReceipt.State == 5 || authorityReceipt.State == 6) ? authorityReceipt.State : (ledger.Committed ? 1 : 2)));
				authorityReceipt.Applied = true;
				authorityReceipt.Save(zdo, ledger.Token);
			}
		}

		internal static AuthorityReceipt Read(ZDO zdo, string token)
		{
			string text = AuthorityState.Read(zdo, "receipt-" + token);
			if (text.Length == 0)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(text));
			using BinaryReader binaryReader = new BinaryReader(memoryStream);
			byte b = binaryReader.ReadByte();
			if (b != 1 && b != 2)
			{
				throw new InvalidDataException("Receipt version");
			}
			AuthorityReceipt authorityReceipt = new AuthorityReceipt
			{
				Actor = binaryReader.ReadString(),
				Fingerprint = binaryReader.ReadString(),
				State = binaryReader.ReadByte(),
				Applied = binaryReader.ReadBoolean()
			};
			if (b >= 2)
			{
				authorityReceipt.Epoch = binaryReader.ReadString();
				authorityReceipt.CharacterConsumed = binaryReader.ReadBoolean();
			}
			else
			{
				authorityReceipt.CharacterConsumed = authorityReceipt.State == 1 || authorityReceipt.State == 5;
			}
			if (authorityReceipt.Actor.Length == 0 || authorityReceipt.Actor.Length > 128 || authorityReceipt.Fingerprint.Length != 44 || authorityReceipt.Epoch.Length > 128 || authorityReceipt.State > 6 || memoryStream.Position != memoryStream.Length)
			{
				throw new InvalidDataException("Receipt state");
			}
			return authorityReceipt;
		}

		internal void Save(ZDO zdo, string token)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write((byte)2);
			binaryWriter.Write(Actor);
			binaryWriter.Write(Fingerprint);
			binaryWriter.Write(State);
			binaryWriter.Write(Applied);
			binaryWriter.Write(Epoch);
			binaryWriter.Write(CharacterConsumed);
			AuthorityState.Write(zdo, "receipt-" + token, Convert.ToBase64String(memoryStream.ToArray()));
		}
	}
	internal static class AuthorityState
	{
		private static AuthenticatedStateStore store;

		private static World storedWorld;

		private static string storedPath;

		private static FileSource storedSource;

		internal static bool IsAuthority
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		private static AuthenticatedStateStore Store
		{
			get
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Invalid comparison between Unknown and I4
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Expected O, but got Unknown
				//IL_014a: Unknown result type (might be due to invalid IL or missing references)
				//IL_014f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: Invalid comparison between Unknown and I4
				//IL_0102: Unknown result type (might be due to invalid IL or missing references)
				//IL_010d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Expected O, but got Unknown
				World world = ZNet.World;
				if (world == null)
				{
					throw new InvalidOperationException("Authority world save is unavailable");
				}
				string text = (world.IsChunkedSave() ? Path.Combine(world.GetSaveDirectory(world.m_fileSource), "Barter.Authority") : (world.GetDBPath() + ".Barter.Authority"));
				if (store == null || storedWorld != world || storedPath != text || storedSource != world.m_fileSource)
				{
					AuthenticatedStateStore val = new AuthenticatedStateStore(text, (IAuthorityStorage)(object)(((int)world.m_fileSource == 4) ? new WorldAuthorityStorage(world.m_fileSource) : null), world.m_needsDB || FileHelpers.Exists(world.GetDBPath(), world.m_fileSource));
					if (store != null && storedWorld == world)
					{
						val.ImportFrom(Plugin.Session.WorldId, store, true);
					}
					else if (world.IsChunkedSave())
					{
						val.ImportFrom(Plugin.Session.WorldId, new AuthenticatedStateStore(world.GetDBPath() + ".Barter.Authority", (IAuthorityStorage)(object)(((int)world.m_fileSource == 4) ? new WorldAuthorityStorage(world.m_fileSource) : null), false), false);
					}
					val.ImportLocal(Plugin.Session.WorldId, Path.Combine(Paths.ConfigPath, "Barter.Authority"));
					store = val;
					storedWorld = world;
					storedPath = text;
					storedSource = world.m_fileSource;
				}
				return store;
			}
		}

		private static string ObjectId(ZDO zdo)
		{
			return ((ZDOID)(ref zdo.m_uid)).UserID.ToString(CultureInfo.InvariantCulture) + ":" + ((ZDOID)(ref zdo.m_uid)).ID.ToString(CultureInfo.InvariantCulture);
		}

		internal unsafe static string Read(ZDO zdo, string field, string displayMirror = "")
		{
			//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)
			Span val = RefillTiming.Measure((Operation)0);
			try
			{
				if (!IsAuthority)
				{
					return displayMirror;
				}
				if (zdo == null || !Plugin.IsReady || !Plugin.Session.AuthorityReady)
				{
					throw new InvalidOperationException("Authority state is unavailable");
				}
				zdo.SetOwner(ZDOMan.GetSessionID());
				return Store.Read(Plugin.Session.WorldId, ObjectId(zdo), field);
			}
			finally
			{
				((IDisposable)(*(Span*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		internal unsafe static void Write(ZDO zdo, string field, string value)
		{
			//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)
			Span val = RefillTiming.Measure((Operation)1);
			try
			{
				if (!IsAuthority || zdo == null || !Plugin.IsReady || !Plugin.Session.AuthorityReady)
				{
					throw new InvalidOperationException("Only the ready authority writes trader state");
				}
				zdo.SetOwner(ZDOMan.GetSessionID());
				Store.Write(Plugin.Session.WorldId, ObjectId(zdo), field, value);
			}
			finally
			{
				((IDisposable)(*(Span*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		internal static string[] Fields(ZDO zdo, string prefix)
		{
			if (!IsAuthority || zdo == null || !Plugin.IsReady || !Plugin.Session.AuthorityReady)
			{
				throw new InvalidOperationException("Authority state is unavailable");
			}
			return Store.Fields(Plugin.Session.WorldId, ObjectId(zdo), prefix);
		}

		internal static void Remove(ZDO zdo, string field)
		{
			if (!IsAuthority || zdo == null || !Plugin.IsReady || !Plugin.Session.AuthorityReady)
			{
				throw new InvalidOperationException("Authority state is unavailable");
			}
			Store.Remove(Plugin.Session.WorldId, ObjectId(zdo), field);
		}
	}
	internal static class BarterOperations
	{
		internal const string ReserveId = "meadworks.barter.reserve";

		internal const string FinishId = "meadworks.barter.finish";

		internal const string EditListId = "meadworks.barter.edit_list";

		internal const string RecoverId = "meadworks.barter.recover";

		private static readonly Version Protocol = new Version(1, 0);

		internal static readonly OperationDescriptor Reserve = new OperationDescriptor("meadworks.barter.reserve", Protocol);

		internal static readonly OperationDescriptor Finish = new OperationDescriptor("meadworks.barter.finish", Protocol);

		internal static readonly OperationDescriptor EditList = new OperationDescriptor("meadworks.barter.edit_list", Protocol);

		internal static readonly OperationDescriptor Recover = new OperationDescriptor("meadworks.barter.recover", Protocol);
	}
	internal static class BuyService
	{
		private static bool busy;

		private static int pendingGeneration;

		internal static void ResetPending()
		{
			busy = false;
			pendingGeneration++;
		}

		internal static void Buy(StoreGui store, TradeItem item, OfferInfo info)
		{
			if (busy || (Object)(object)store == (Object)null || (Object)(object)store.m_trader == (Object)null || item == null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			Player player = Player.m_localPlayer;
			if ((Object)(object)item.m_prefab == (Object)null || !string.IsNullOrEmpty(item.m_buyKey) || !string.IsNullOrEmpty(item.m_incrementKey))
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning("Barter refused a native key or inventory-upgrade reward; atomic reward rollback is not qualified.");
				}
				((Character)player).Message((MessageType)2, TradeAuthority.UnavailableReason, 0, (Sprite)null, false);
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (OptionalTradeIntegrations.InventoryHeld(inventory))
			{
				((Character)player).Message((MessageType)2, BarterText.Text("trade_inventory_held"), 0, (Sprite)null, false);
				return;
			}
			if (TradeAuthority.RecoveryBlocked || SafeTradeInventory.IsBlocked(inventory))
			{
				((Character)player).Message((MessageType)2, TradeAuthority.UnavailableReason, 0, (Sprite)null, false);
				return;
			}
			Trader trader = store.m_trader;
			ItemDrop currency = TradeOffers.CurrencyOf(info, store);
			int price = item.m_price;
			bool flag = info?.FromList ?? false;
			int stack = (flag ? item.m_stack : Math.Min(item.m_stack, item.m_prefab.m_itemData.m_shared.m_maxStackSize));
			int quality = ((info != null && info.Quality > 0) ? info.Quality : item.m_prefab.m_itemData.m_quality);
			if ((Object)(object)currency == (Object)null || price < 0 || stack <= 0)
			{
				return;
			}
			if (Currencies.Count(inventory, currency) < price)
			{
				((Character)player).Message((MessageType)2, BarterText.Format("buy_need", price, Currencies.Name(currency)), 0, (Sprite)null, false);
				return;
			}
			TradeRequest request = new TradeRequest
			{
				Buy = true,
				Vanilla = !flag,
				Prefab = Utils.GetPrefabName(((Component)item.m_prefab).gameObject),
				Currency = Utils.GetPrefabName(((Component)currency).gameObject),
				Amount = stack,
				Quality = quality,
				LotSize = stack,
				Price = price
			};
			busy = true;
			int attempt = ++pendingGeneration;
			if (!TradeAuthority.TryBegin(store, request, delegate(TradePermit permit)
			{
				//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01de: Unknown result type (might be due to invalid IL or missing references)
				//IL_0202: Unknown result type (might be due to invalid IL or missing references)
				//IL_0207: Unknown result type (might be due to invalid IL or missing references)
				//IL_0215: Unknown result type (might be due to invalid IL or missing references)
				//IL_021b: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (attempt != pendingGeneration)
					{
						permit?.Finish(success: false);
					}
					else if (permit == null)
					{
						((Character)player).Message((MessageType)2, TradeAuthority.UnavailableReason, 0, (Sprite)null, false);
					}
					else if (!permit.IsCurrent || (Object)(object)Player.m_localPlayer != (Object)(object)player || (Object)(object)store == (Object)null || (Object)(object)store.m_trader != (Object)(object)trader || ((Humanoid)player).GetInventory() != inventory || !StoreGui.IsVisible())
					{
						permit.Finish(success: false);
					}
					else
					{
						List<SafeTradeInventory.Take> list = SafeTradeInventory.Currency(inventory, currency, price);
						if (((IEnumerable<SafeTradeInventory.Take>)list).Sum((Func<SafeTradeInventory.Take, long>)((SafeTradeInventory.Take take) => take.Amount)) != price)
						{
							permit.Finish(success: false);
						}
						else
						{
							bool cheated = list.Any((SafeTradeInventory.Take take) => take.Item.m_cheated);
							ItemData val = SafeTradeInventory.Template(item.m_prefab, quality, cheated);
							ExchangeResult exchangeResult = SafeTradeInventory.Exchange(inventory, list, val, stack);
							if (exchangeResult == ExchangeResult.Unresolved)
							{
								MeadworksLog log2 = Plugin.Log;
								if (log2 != null)
								{
									log2.Warning("Trade inventory rollback could not be proven; the server reservation remains locked for recovery.");
								}
							}
							else
							{
								permit.Finish(exchangeResult == ExchangeResult.Completed);
								if (exchangeResult != ExchangeResult.Completed)
								{
									((Character)player).Message((MessageType)2, BarterText.Text((exchangeResult == ExchangeResult.InventoryHeld) ? "trade_inventory_held" : "buy_no_room"), 0, (Sprite)null, false);
								}
								else
								{
									trader.OnBought(item);
									store.m_buyEffects.Create(((Component)store).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
									EffectList buyPlayerEffects = item.m_buyPlayerEffects;
									if (buyPlayerEffects != null)
									{
										buyPlayerEffects.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
									}
									if (item.m_levelUpEffect)
									{
										player.OnSkillLevelup((SkillType)0, 0f);
									}
									((Character)player).ShowPickupMessage(val, stack);
									Gogan.LogEvent("Game", "BoughtItem", ((Object)item.m_prefab).name, 0L);
								}
							}
						}
					}
				}
				finally
				{
					if (attempt == pendingGeneration)
					{
						busy = false;
					}
					if ((Object)(object)store != (Object)null && (Object)(object)store.m_trader == (Object)(object)trader && StoreGui.IsVisible())
					{
						store.FillList();
					}
				}
			}))
			{
				busy = false;
				((Character)player).Message((MessageType)2, TradeAuthority.UnavailableReason, 0, (Sprite)null, false);
			}
		}
	}
	internal static class Currencies
	{
		private static ItemDrop vanilla;

		private static readonly HashSet<string> warned = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal static ItemDrop Vanilla(StoreGui store = null)
		{
			if ((Object)(object)vanilla != (Object)null)
			{
				return vanilla;
			}
			vanilla = (ItemDrop)(((Object)(object)store != (Object)null && (Object)(object)store.m_coinPrefab != (Object)null && ((Object)store.m_coinPrefab).name == "Coins") ? ((object)store.m_coinPrefab) : ((object)TradeWorld.Item("Coins")));
			return vanilla;
		}

		internal static string NameFor(string trader)
		{
			string text = default(string);
			string fallback = CurrencyRules.ForTrader(Plugin.Settings.Get<string>(Lists.TraderCurrencies), trader, ref text);
			if (text != null && warned.Add(text))
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning(text);
				}
			}
			return TraderPolicies.Currency(trader, fallback);
		}

		internal static ItemDrop Resolve(string prefab, ItemDrop fallback)
		{
			if (CurrencyRules.IsVanilla(prefab))
			{
				return Vanilla();
			}
			ItemDrop val = TradeWorld.Item(prefab);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			if (warned.Add("missing:" + prefab))
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning("Currency item prefab '" + prefab + "' was not found. The trader's default currency will be used.");
				}
			}
			return fallback ?? Vanilla();
		}

		internal static ItemDrop OfTrader(string trader)
		{
			return Resolve(NameFor(trader), Vanilla());
		}

		internal static ItemDrop Apply(StoreGui store, Trader trader)
		{
			if ((Object)(object)store == (Object)null)
			{
				return null;
			}
			Vanilla(store);
			ItemDrop val = (((Object)(object)trader == (Object)null) ? Vanilla() : OfTrader(TradeWorld.TraderName(trader)));
			if ((Object)(object)val == (Object)null)
			{
				val = Vanilla();
			}
			if ((Object)(object)val != (Object)null)
			{
				store.m_coinPrefab = val;
				SetIcons(store.m_rootPanel, val);
			}
			return val;
		}

		internal static void Restore(StoreGui store)
		{
			if ((Object)(object)store != (Object)null)
			{
				ItemDrop val = vanilla ?? TradeWorld.Item("Coins");
				if ((Object)(object)val != (Object)null)
				{
					store.m_coinPrefab = val;
					SetIcons(store.m_rootPanel, val);
				}
			}
		}

		internal static int Count(Inventory inventory, ItemDrop currency)
		{
			if (inventory != null && !((Object)(object)currency == (Object)null))
			{
				return inventory.CountItems(currency.m_itemData.m_shared.m_name, -1, true);
			}
			return 0;
		}

		internal static void SetIcons(GameObject root, ItemDrop currency)
		{
			if ((Object)(object)root == (Object)null || (Object)(object)currency == (Object)null)
			{
				return;
			}
			Sprite icon = currency.m_itemData.GetIcon();
			Image[] componentsInChildren = root.GetComponentsInChildren<Image>(true);
			foreach (Image val in componentsInChildren)
			{
				string name = ((Object)((Component)val).gameObject).name;
				if (name.IndexOf("coin", StringComparison.OrdinalIgnoreCase) >= 0 && name.IndexOf("bkg", StringComparison.OrdinalIgnoreCase) < 0)
				{
					val.sprite = icon;
				}
			}
		}

		internal static string Name(ItemDrop currency)
		{
			if (!((Object)(object)currency == (Object)null))
			{
				return Localization.instance.Localize(currency.m_itemData.m_shared.m_name);
			}
			return string.Empty;
		}
	}
	internal static class OptionalTradeIntegrations
	{
		internal const string EpicLootGuid = "randyknapp.mods.epicloot";

		internal const string ExtraSlotsGuid = "shudnal.ExtraSlots";

		internal const string AzuSlotsGuid = "Azumatt.AzuExtendedPlayerInventory";

		private static readonly Dictionary<string, object> plugins = new Dictionary<string, object>();

		private static readonly HashSet<string> warned = new HashSet<string>();

		private const string BurrowHoldId = "meadworks.burrow.inventory_hold";

		private const string BurrowOwner = "com.meadworks.burrow";

		internal static bool EpicLootAdventure
		{
			get
			{
				if (!plugins.TryGetValue("randyknapp.mods.epicloot", out object value))
				{
					return false;
				}
				try
				{
					MethodInfo method = value.GetType().GetMethod("IsAdventureModeEnabled", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					if (method == null || method.ReturnType != typeof(bool))
					{
						throw new MissingMethodException("IsAdventureModeEnabled");
					}
					return (bool)method.Invoke(method.IsStatic ? null : value, null);
				}
				catch (Exception error)
				{
					Warn("randyknapp.mods.epicloot", error);
					return true;
				}
			}
		}

		internal static bool InventoryHeld(Inventory inventory)
		{
			if (inventory == null || !Plugin.IsReady)
			{
				return false;
			}
			try
			{
				CapabilityRegistry capabilities = Plugin.Services.Capabilities;
				IReadOnlyList<CapabilityMetadata> readOnlyList = capabilities.Providers("meadworks.burrow.inventory_hold");
				if (readOnlyList.Count == 0)
				{
					return false;
				}
				Func<object, bool> func = default(Func<object, bool>);
				if (readOnlyList.Count != 1 || readOnlyList[0].Owner != "com.meadworks.burrow" || !capabilities.TryResolve<Func<object, bool>>("meadworks.burrow.inventory_hold", new Version(1, 0), ref func) || func == null)
				{
					throw new InvalidOperationException("Burrow inventory hold contract unavailable.");
				}
				return func(inventory);
			}
			catch (Exception error)
			{
				Warn("com.meadworks.burrow", error);
				return true;
			}
		}

		internal static void Initialize()
		{
			Shutdown();
			string[] array = new string[3] { "randyknapp.mods.epicloot", "shudnal.ExtraSlots", "Azumatt.AzuExtendedPlayerInventory" };
			foreach (string key in array)
			{
				if (Chainloader.PluginInfos.TryGetValue(key, out var value))
				{
					plugins[key] = value.Instance;
				}
			}
		}

		internal static bool ProtectedItem(ItemData item, Player player)
		{
			if (item == null)
			{
				return true;
			}
			string[] array = new string[2] { "shudnal.ExtraSlots", "Azumatt.AzuExtendedPlayerInventory" };
			foreach (string text in array)
			{
				if (!plugins.TryGetValue(text, out object value))
				{
					continue;
				}
				try
				{
					if (text == "shudnal.ExtraSlots")
					{
						MethodInfo method = (value.GetType().Assembly.GetType("ExtraSlots.API") ?? throw new TypeLoadException("ExtraSlots.API")).GetMethod("GetAllExtraSlotsItems", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
						if (method == null || !(method.Invoke(null, null) is IEnumerable enumerable))
						{
							throw new MissingMethodException("GetAllExtraSlotsItems");
						}
						foreach (object item2 in enumerable)
						{
							if (item == item2)
							{
								return true;
							}
						}
						continue;
					}
					object obj = (value.GetType().Assembly.GetType("AzuExtendedPlayerInventory.API") ?? throw new TypeLoadException("AzuExtendedPlayerInventory.API")).GetMethod("GetSlots", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null)?.Invoke(null, null) ?? throw new MissingMethodException("GetSlots");
					foreach (object item3 in ((obj.GetType().GetField("GetItemFuncs")?.GetValue(obj) ?? obj.GetType().GetProperty("GetItemFuncs")?.GetValue(obj)) as IEnumerable) ?? throw new MissingMemberException("GetItemFuncs"))
					{
						if (item3 != null && ((item3 as Delegate) ?? throw new InvalidOperationException("Unexpected slot callback type.")).DynamicInvoke(player) == item)
						{
							return true;
						}
					}
				}
				catch (Exception error)
				{
					Warn(text, error);
					return true;
				}
			}
			return false;
		}

		private static void Warn(string guid, Exception error)
		{
			if (warned.Add(guid))
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning("Optional trader integration unavailable for " + guid + ": " + error.GetType().Name + ". Barter keeps protected items and foreign panels safe.");
				}
			}
		}

		internal static void Shutdown()
		{
			plugins.Clear();
			warned.Clear();
		}
	}
	[HarmonyPatch(typeof(Player), "Load")]
	internal static class Player_Load_BarterRecovery
	{
		private static void Prefix(Player __instance)
		{
			TradeAuthority.BeforeCharacterLoad(__instance);
		}

		private static void Postfix(Player __instance)
		{
			TradeAuthority.CharacterLoaded(__instance);
		}
	}
	internal static class Purses
	{
		private static readonly int BalanceKey = StringExtensionMethods.GetStableHashCode("traderCoins");

		private static readonly int DayKey = StringExtensionMethods.GetStableHashCode("traderCoinsReplenished");

		private static readonly int LedgerKey = StringExtensionMethods.GetStableHashCode("meadworks.barter.ledger.v1");

		internal static bool HasPurse(string trader)
		{
			if (string.IsNullOrEmpty(trader) || Plugin.Settings == null)
			{
				return false;
			}
			if (TraderNames.Vanilla.Any((string name) => TraderNames.Normalize(name) == trader))
			{
				return true;
			}
			if (TraderNames.ListContains(Plugin.Settings.Get<string>(Lists.CustomTraders), trader))
			{
				return true;
			}
			if (!TradeLists.Written.Traders.Contains(trader))
			{
				return TraderPolicies.HasTrader(trader);
			}
			return true;
		}

		internal static PurseRules Rules(string trader)
		{
			PurseRules val = Plugin.Settings.Purse();
			val.Enabled = TraderPolicies.Get(Purse.Enabled, trader, val.Enabled);
			val.Flexible = TraderPolicies.Get(Purse.FlexiblePricing, trader, val.Flexible);
			val.Minimum = TraderPolicies.Get(Purse.MinimumBalance, trader, val.Minimum);
			val.Maximum = TraderPolicies.Get(Purse.MaximumBalance, trader, val.Maximum);
			val.DailyIncrease = TraderPolicies.Get(Purse.DailyIncrease, trader, val.DailyIncrease);
			val.DailyDecrease = TraderPolicies.Get(Purse.DailyDecrease, trader, val.DailyDecrease);
			val.Discount = TraderPolicies.Get(Purse.Discount, trader, val.Discount);
			val.Markup = TraderPolicies.Get(Purse.Markup, trader, val.Markup);
			val.ReplenishDays = TraderPolicies.Get(Purse.ReplenishDays, trader, val.ReplenishDays);
			if (!HasPurse(trader))
			{
				val.Enabled = false;
			}
			return val;
		}

		internal static bool Applies(Trader trader)
		{
			return Rules(TradeWorld.TraderName(trader)).Enabled;
		}

		internal static int Balance(Trader trader, ZDO authorityZdo = null)
		{
			int num = PurseRefill.Initial(Rules(TradeWorld.TraderName(trader)));
			if (authorityZdo != null)
			{
				return ReadLedger(authorityZdo, num).Balance;
			}
			ZNetView val = (((Object)(object)trader != (Object)null) ? ((Component)trader).GetComponent<ZNetView>() : null);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return num;
			}
			return ReadLedger(val.GetZDO(), num).Balance;
		}

		internal static float BuyFactor(Trader trader, ZDO authorityZdo = null)
		{
			PurseRules val = Rules(TradeWorld.TraderName(trader));
			if (!val.Enabled)
			{
				return 1f;
			}
			return PriceCurve.BuyFactor(Balance(trader, authorityZdo), val);
		}

		internal static float SellFactor(Trader trader, ZDO authorityZdo = null)
		{
			PurseRules val = Rules(TradeWorld.TraderName(trader));
			if (!val.Enabled)
			{
				return 1f;
			}
			return PriceCurve.SellFactor(Balance(trader, authorityZdo), val);
		}

		internal static bool CanPay(Trader trader, int amount)
		{
			if (amount > 0)
			{
				if (Applies(trader))
				{
					return amount <= Balance(trader);
				}
				return true;
			}
			return false;
		}

		internal static void Change(Trader trader, long delta)
		{
			if (delta != 0L)
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning("Ignored purse write outside the trade authority protocol.");
				}
			}
		}

		internal static PurseLedger ReadLedger(ZDO zdo, int initial)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			string text = AuthorityState.Read(zdo, "ledger", zdo.GetString(LedgerKey, ""));
			PurseLedger val = (PurseLedger)((text.Length != 0) ? ((object)PurseLedger.Decode(text)) : ((object)new PurseLedger(initial)));
			if (AuthorityState.IsAuthority)
			{
				if (text.Length == 0)
				{
					AuthorityState.Write(zdo, "untrusted-legacy-ledger", zdo.GetString(LedgerKey, "") + "\n" + zdo.GetInt(BalanceKey, initial).ToString(CultureInfo.InvariantCulture));
					AuthorityState.Write(zdo, "ledger", val.Encode());
				}
				if (val.QuarantineExpired(DateTimeOffset.UtcNow.ToUnixTimeSeconds(), 120))
				{
					WriteLedger(zdo, val);
				}
				Mirror(zdo, val);
			}
			return val;
		}

		internal static void WriteLedger(ZDO zdo, PurseLedger ledger)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				throw new InvalidOperationException("Only the server writes purse state.");
			}
			AuthorityState.Write(zdo, "ledger", ledger.Encode());
			Mirror(zdo, ledger);
		}

		private static void Mirror(ZDO zdo, PurseLedger ledger)
		{
			zdo.SetOwner(ZDOMan.GetSessionID());
			string text = ledger.Encode();
			if (zdo.GetString(LedgerKey, "") != text)
			{
				zdo.Set(LedgerKey, text);
			}
			if (zdo.GetInt(BalanceKey, -1) != ledger.Balance)
			{
				zdo.Set(BalanceKey, ledger.Balance, false);
			}
		}

		private static int RefillDay(ZDO zdo)
		{
			string text = AuthorityState.Read(zdo, "refill-day");
			if (text.Length == 0)
			{
				return 0;
			}
			if (!int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 0)
			{
				throw new InvalidDataException("Invalid authority refill day");
			}
			return result;
		}

		internal static bool Refill()
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !Object.op_Implicit((Object)(object)EnvMan.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null || Plugin.Settings == null)
			{
				return false;
			}
			bool flag = false;
			int currentDay = EnvMan.instance.GetCurrentDay();
			RefillTiming.SetDay(currentDay);
			Dictionary<int, (string, string)> dictionary = new Dictionary<int, (string, string)>();
			int num = default(int);
			foreach (ZDO item2 in ZDOMan.instance.m_objectsByID.Values.Where((ZDO zdo) => zdo != null))
			{
				RefillTiming.Scanned();
				int prefab = item2.GetPrefab();
				if (!dictionary.TryGetValue(prefab, out var value))
				{
					GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
					string obj = ((prefab2 != null) ? ((Object)prefab2).name : null);
					string text = TraderNames.Normalize(obj);
					value = (obj, (!string.IsNullOrEmpty(obj) && HasPurse(text)) ? text : "");
					dictionary.Add(prefab, value);
				}
				if (value.Item2.Length == 0)
				{
					continue;
				}
				string item = value.Item2;
				PurseRules val = Rules(item);
				if (!val.Enabled)
				{
					continue;
				}
				RefillTiming.Trader();
				PurseLedger val2 = ReadLedger(item2, PurseRefill.Initial(val));
				if (val2.Pending)
				{
					continue;
				}
				int balance = val2.Balance;
				if (PurseRefill.TryReplenish(balance, RefillDay(item2), currentDay, val, ref num) && val2.Refill(num))
				{
					AuthorityState.Write(item2, "refill-day", currentDay.ToString(CultureInfo.InvariantCulture));
					WriteLedger(item2, val2);
					item2.Set(DayKey, currentDay, false);
					RefillTiming.Refilled();
					flag |= TraderPolicies.Get(Purse.ReplenishMessage, item, Plugin.Settings.Get<bool>(Purse.ReplenishMessage));
					MeadworksLog log = Plugin.Log;
					if (log != null)
					{
						log.Verbose($"{value.Item1} balance updated {balance} -> {num}");
					}
				}
			}
			return flag;
		}
	}
	internal enum ExchangeResult
	{
		Completed,
		RolledBack,
		Unresolved,
		InventoryHeld
	}
	internal static class SafeTradeInventory
	{
		private sealed class PendingAdd
		{
			internal Inventory Inventory;

			internal ItemData Template;

			internal ItemData Item;

			internal Vector2i Position;

			internal int Amount;
		}

		internal readonly struct Take
		{
			internal ItemData Item { get; }

			internal int Amount { get; }

			internal Take(ItemData item, int amount)
			{
				Item = item;
				Amount = amount;
			}
		}

		private sealed class Delta
		{
			internal ItemData Item;

			internal int Amount;

			internal Vector2i Position;

			internal bool Added;

			internal bool Repaired;

			internal float BeforeDurability;

			internal float AfterDurability;
		}

		private static readonly Dictionary<Inventory, List<Delta>> unresolved = new Dictionary<Inventory, List<Delta>>();

		private const int RecoveryLimit = 64;

		private static PendingAdd adding;

		internal static bool IsBlocked(Inventory inventory)
		{
			if (inventory != null)
			{
				if (!unresolved.ContainsKey(inventory))
				{
					return unresolved.Count >= 64;
				}
				return true;
			}
			return false;
		}

		internal static void ObserveBeforeChanged(Inventory inventory)
		{
			PendingAdd pendingAdd = adding;
			if (pendingAdd != null && pendingAdd.Inventory == inventory && pendingAdd.Item == null)
			{
				ItemData itemAt = inventory.GetItemAt(pendingAdd.Position.x, pendingAdd.Position.y);
				if (itemAt != null && itemAt.m_shared == pendingAdd.Template.m_shared && itemAt.m_quality == pendingAdd.Template.m_quality && !((Object)(object)itemAt.m_dropPrefab != (Object)(object)pendingAdd.Template.m_dropPrefab))
				{
					pendingAdd.Item = itemAt;
					pendingAdd.Amount = itemAt.m_stack;
				}
			}
		}

		internal static IReadOnlyList<Take> RecoveryItems(Inventory inventory)
		{
			if (!unresolved.TryGetValue(inventory, out List<Delta> value))
			{
				return Array.Empty<Take>();
			}
			return (from delta in value
				where !delta.Added && delta.Amount > 0
				select new Take(delta.Item, delta.Amount)).ToArray();
		}

		internal static List<Take> Currency(Inventory inventory, ItemDrop currency, int amount)
		{
			List<Take> list = new List<Take>();
			if (inventory == null || (Object)(object)currency == (Object)null || amount < 0)
			{
				return list;
			}
			ItemData[] array = inventory.GetAllItems().ToArray();
			foreach (ItemData val in array)
			{
				if (!((Object)(object)val.m_dropPrefab == (Object)null) && !(Utils.GetPrefabName(val.m_dropPrefab) != Utils.GetPrefabName(((Component)currency).gameObject)) && !(val.m_shared.m_name != currency.m_itemData.m_shared.m_name) && val.m_worldLevel >= Game.m_worldLevel && !val.m_equipped && !OptionalTradeIntegrations.ProtectedItem(val, Player.m_localPlayer))
				{
					int num = Math.Min(amount, val.m_stack);
					if (num > 0)
					{
						list.Add(new Take(val, num));
					}
					amount -= num;
					if (amount == 0)
					{
						break;
					}
				}
			}
			if (amount != 0)
			{
				return new List<Take>();
			}
			return list;
		}

		internal static ItemData Template(ItemDrop prefab, int quality, bool cheated)
		{
			ItemData val = prefab.m_itemData.Clone();
			val.m_dropPrefab = ((Component)prefab).gameObject;
			val.m_quality = ((quality > 0) ? quality : val.m_quality);
			val.m_durability = val.GetMaxDurability();
			val.m_worldLevel = Game.m_worldLevel;
			val.m_cheated = cheated;
			val.m_equipped = false;
			val.m_stack = 1;
			return val;
		}

		internal static bool CanFitExchange(Inventory inventory, IReadOnlyList<Take> payment, ItemData output, int amount)
		{
			if (inventory == null || payment == null || output == null || amount < 0)
			{
				return false;
			}
			long num = inventory.GetEmptySlots();
			HashSet<ItemData> hashSet = new HashSet<ItemData>();
			foreach (Take item in payment)
			{
				if (item.Item == null || item.Amount <= 0 || !hashSet.Add(item.Item) || !inventory.ContainsItem(item.Item) || item.Item.m_stack < item.Amount || item.Item.m_equipped || OptionalTradeIntegrations.ProtectedItem(item.Item, Player.m_localPlayer))
				{
					return false;
				}
				if (item.Amount == item.Item.m_stack)
				{
					num++;
				}
			}
			long num2 = ((long)amount + (long)Math.Max(1, output.m_shared.m_maxStackSize) - 1) / Math.Max(1, output.m_shared.m_maxStackSize);
			return num >= num2;
		}

		internal static ExchangeResult Exchange(Inventory inventory, IReadOnlyList<Take> payment, ItemData output, int amount)
		{
			return ExchangeMany(inventory, payment, (output == null) ? null : new Take[1]
			{
				new Take(output, amount)
			});
		}

		internal static ExchangeResult Repair(Inventory inventory, IReadOnlyList<Take> payment, ItemData item)
		{
			return ExchangeMany(inventory, payment, Array.Empty<Take>(), item);
		}

		internal static ExchangeResult ExchangeMany(Inventory inventory, IReadOnlyList<Take> payment, IReadOnlyList<Take> outputs, ItemData repair = null)
		{
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			if (inventory == null || outputs == null || outputs.Any((Take o) => o.Item == null || o.Amount < 0) || payment == null)
			{
				return ExchangeResult.RolledBack;
			}
			if (IsBlocked(inventory))
			{
				return ExchangeResult.Unresolved;
			}
			if (OptionalTradeIntegrations.InventoryHeld(inventory))
			{
				return ExchangeResult.InventoryHeld;
			}
			if (repair != null && (!inventory.ContainsItem(repair) || repair.m_stack != 1 || payment.Any((Take t) => t.Item == repair)))
			{
				return ExchangeResult.RolledBack;
			}
			float num = repair?.m_durability ?? 0f;
			HashSet<ItemData> hashSet = new HashSet<ItemData>();
			foreach (Take item2 in payment)
			{
				if (item2.Item == null || item2.Amount <= 0 || !hashSet.Add(item2.Item) || !inventory.ContainsItem(item2.Item) || item2.Item.m_stack < item2.Amount || item2.Item.m_equipped || OptionalTradeIntegrations.ProtectedItem(item2.Item, Player.m_localPlayer))
				{
					return ExchangeResult.RolledBack;
				}
			}
			List<Delta> list = new List<Delta>();
			bool flag = false;
			try
			{
				foreach (Take item3 in payment)
				{
					if (item3.Item.m_equipped || OptionalTradeIntegrations.ProtectedItem(item3.Item, Player.m_localPlayer))
					{
						return Rollback(inventory, list);
					}
					int stack = item3.Item.m_stack;
					Delta delta = new Delta
					{
						Item = item3.Item,
						Position = item3.Item.m_gridPos
					};
					try
					{
						inventory.RemoveItem(item3.Item, item3.Amount);
					}
					finally
					{
						delta.Amount = Math.Max(0, stack - (inventory.ContainsItem(item3.Item) ? item3.Item.m_stack : 0));
						if (delta.Amount > 0)
						{
							list.Add(delta);
						}
					}
					if (delta.Amount != item3.Amount)
					{
						return Refused(inventory, list);
					}
				}
				foreach (Take output in outputs)
				{
					int num2 = output.Amount;
					while (num2 > 0)
					{
						ItemData item = output.Item;
						Vector2i val = inventory.FindEmptySlot(false);
						if (val.x < 0)
						{
							return Rollback(inventory, list);
						}
						int num3 = Math.Min(num2, Math.Max(1, item.m_shared.m_maxStackSize));
						ItemData val2 = item.Clone();
						val2.m_stack = num3;
						int num4 = 0;
						PendingAdd pendingAdd = adding;
						PendingAdd pendingAdd2 = (adding = new PendingAdd
						{
							Inventory = inventory,
							Position = val,
							Template = val2
						});
						bool flag2 = false;
						bool flag3 = false;
						try
						{
							flag2 = inventory.AddItem(val2, num3, val.x, val.y, false);
							flag3 = true;
						}
						finally
						{
							adding = pendingAdd;
							if (pendingAdd2.Item != null)
							{
								int num5 = Math.Min(num3, pendingAdd2.Amount);
								num4 = (inventory.ContainsItem(pendingAdd2.Item) ? Math.Min(num5, pendingAdd2.Item.m_stack) : 0);
								list.Add(new Delta
								{
									Item = pendingAdd2.Item,
									Amount = num5,
									Added = true
								});
							}
							else if (flag2 || !flag3 || inventory.GetItemAt(val.x, val.y) != null)
							{
								flag = true;
							}
						}
						if (flag)
						{
							return KeepUnresolved(inventory, list);
						}
						if (num4 != num3)
						{
							return Refused(inventory, list);
						}
						num2 -= num3;
					}
				}
				if (repair != null)
				{
					if (!inventory.ContainsItem(repair) || repair.m_durability != num)
					{
						return Rollback(inventory, list);
					}
					Delta delta2 = new Delta
					{
						Item = repair,
						Repaired = true,
						BeforeDurability = repair.m_durability,
						AfterDurability = repair.GetMaxDurability()
					};
					list.Add(delta2);
					repair.m_durability = delta2.AfterDurability;
					inventory.Changed(false, false);
					if (!inventory.ContainsItem(repair) || repair.m_durability != delta2.AfterDurability)
					{
						return KeepUnresolved(inventory, list);
					}
				}
				return ExchangeResult.Completed;
			}
			catch (Exception)
			{
				return flag ? KeepUnresolved(inventory, list) : Rollback(inventory, list);
			}
		}

		private static ExchangeResult Rollback(Inventory inventory, List<Delta> deltas)
		{
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				foreach (Delta item3 in deltas.Where((Delta d) => d.Repaired).Reverse())
				{
					if (!inventory.ContainsItem(item3.Item) || item3.Item.m_durability != item3.AfterDurability)
					{
						return KeepUnresolved(inventory, deltas);
					}
					item3.Item.m_durability = item3.BeforeDurability;
					item3.Repaired = false;
				}
				foreach (Delta item4 in deltas.Where((Delta d) => d.Added).Reverse())
				{
					if (!inventory.ContainsItem(item4.Item) || item4.Item.m_stack < item4.Amount)
					{
						return KeepUnresolved(inventory, deltas);
					}
					ItemData item = item4.Item;
					item.m_stack -= item4.Amount;
					if (item4.Item.m_stack == 0)
					{
						inventory.m_inventory.Remove(item4.Item);
					}
					item4.Amount = 0;
				}
				foreach (Delta item5 in deltas.Where((Delta d) => !d.Added).Reverse())
				{
					if (inventory.ContainsItem(item5.Item))
					{
						ItemData item2 = item5.Item;
						item2.m_stack += item5.Amount;
					}
					else
					{
						Vector2i val = ((inventory.GetItemAt(item5.Position.x, item5.Position.y) == null) ? item5.Position : inventory.FindEmptySlot(false));
						if (val.x < 0)
						{
							return KeepUnresolved(inventory, deltas);
						}
						item5.Item.m_stack = item5.Amount;
						item5.Item.m_gridPos = val;
						inventory.m_inventory.Add(item5.Item);
					}
					item5.Amount = 0;
				}
				inventory.Changed(false, false);
				return ExchangeResult.RolledBack;
			}
			catch (Exception)
			{
				return KeepUnresolved(inventory, deltas);
			}
		}

		private static ExchangeResult Refused(Inventory inventory, List<Delta> deltas)
		{
			bool num = OptionalTradeIntegrations.InventoryHeld(inventory);
			ExchangeResult exchangeResult = Rollback(inventory, deltas);
			if (!num || exchangeResult != ExchangeResult.RolledBack)
			{
				return exchangeResult;
			}
			return ExchangeResult.InventoryHeld;
		}

		private static ExchangeResult KeepUnresolved(Inventory inventory, List<Delta> deltas)
		{
			unresolved[inventory] = deltas;
			return ExchangeResult.Unresolved;
		}
	}
	internal static class SellService
	{
		private static readonly List<SellOffer> offers = new List<SellOffer>();

		private static SellOffer selected;

		private static bool busy;

		private static int pendingGeneration;

		internal static IReadOnlyList<SellOffer> Offers => offers;

		internal static SellOffer Selected => selected;

		internal static string Filter { get; set; } = string.Empty;

		internal static long Revision { get; private set; }

		internal static void ResetPending()
		{
			busy = false;
			pendingGeneration++;
		}

		internal static void Clear()
		{
			offers.Clear();
			selected = null;
			Filter = string.Empty;
			Revision++;
		}

		internal static void Refresh(StoreGui store)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Expected O, but got Unknown
			SellOffer previous = selected;
			offers.Clear();
			selected = null;
			try
			{
				Trader val = (((Object)(object)store != (Object)null) ? store.m_trader : null);
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)val == (Object)null || (Object)(object)localPlayer == (Object)null || !Plugin.Active || !TradeLists.Ready || Plugin.Settings == null)
				{
					return;
				}
				string text = TradeWorld.TraderName(val);
				TradeBook effective = TradeLists.Effective;
				bool flag = Plugin.Settings.GetFor<bool>(Lists.CommonValuables, text);
				SellPriceTable val2 = SellPriceTable.Build((IEnumerable<TradeEntry>)effective.Sell(text, flag), (ITradeContext)(object)TradeWorld.Instance);
				SellSettings val3 = new SellSettings(Purses.SellFactor(val), Plugin.Settings.GetFor<float>(Lists.QualityPriceMultiplier, text));
				string traderCurrency = Currencies.NameFor(text);
				ItemDrop own = (ItemDrop)(((Object)(object)store.m_coinPrefab != (Object)null) ? ((object)store.m_coinPrefab) : ((object)Currencies.Vanilla()));
				bool flag2 = Plugin.Settings.Get<bool>(Interface.HideEquipped);
				string text2 = Filter ?? string.Empty;
				List<HeldItem> list = new List<HeldItem>();
				foreach (ItemData item in ((Humanoid)localPlayer).GetInventory().GetAllItemsSortedByName())
				{
					string text3 = TradeWorld.PrefabName(item);
					if (text3.Length != 0 && item.m_worldLevel >= Game.m_worldLevel && !item.m_equipped && !OptionalTradeIntegrations.ProtectedItem(item, localPlayer) && (!flag2 || (!item.m_equipped && (item.m_gridPos.y != 0 || !item.IsEquipable()))) && (text2.Length <= 0 || Localization.instance.Localize(item.m_shared.m_name).IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0))
					{
						list.Add(new HeldItem((object)item, text3, item.m_stack, item.m_quality, item.m_shared.m_maxStackSize));
					}
				}
				offers.AddRange(SellPlanner.Plan((IEnumerable<HeldItem>)list, val2, val3, (Func<string, string>)delegate(string raw)
				{
					ItemDrop val4 = Currencies.Resolve(CurrencyRules.Effective(raw, traderCurrency), own);
					return (!((Object)(object)val4 != (Object)null)) ? null : Utils.GetPrefabName(((Component)val4).gameObject);
				}));
				int num = ((previous == null) ? (-1) : offers.FindIndex((SellOffer offer) => Same(offer, previous)));
				selected = ((num >= 0) ? offers[num] : ((offers.Count > 0) ? offers[0] : null));
			}
			finally
			{
				Revision++;
			}
		}

		internal static void Select(SellOffer offer)
		{
			if (selected != offer)
			{
				selected = offer;
				Revision++;
			}
		}

		internal static int ItemsPerSale(SellOffer offer)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if (offer != null)
			{
				if ((int)offer.Kind != 2)
				{
					if ((int)offer.Kind != 1)
					{
						return 1;
					}
					return offer.Stack;
				}
				return offer.Amount;
			}
			return 0;
		}

		internal static bool CanSell(StoreGui store, out string reason)
		{
			reason = string.Empty;
			SellOffer val = selected;
			if (busy || val == null || (Object)(object)store == (Object)null || (Object)(object)store.m_trader == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			if (TradeAuthority.RecoveryBlocked || SafeTradeInventory.IsBlocked(((Humanoid)Player.m_localPlayer).GetInventory()))
			{
				reason = TradeAuthority.UnavailableReason;
				return false;
			}
			if (OptionalTradeIntegrations.InventoryHeld(((Humanoid)Player.m_localPlayer).GetInventory()))
			{
				reason = BarterText.Text("trade_inventory_held");
				return false;
			}
			if (SameCurrencyAsTrader(val, store) && !Purses.CanPay(store.m_trader, val.Price))
			{
				reason = BarterText.Format("sell_trader_poor", store.m_trader.GetHoverName());
				return false;
			}
			if (!CanReceivePayment(((Humanoid)Player.m_localPlayer).GetInventory(), val.Sources.Cast<ItemData>().ToList(), ItemsPerSale(val), val.Price, TradeWorld.Item(val.Currency) ?? Currencies.Vanilla()))
			{
				reason = BarterText.Text("sell_no_room");
				return false;
			}
			return true;
		}

		internal static void Sell(StoreGui store)
		{
			if (busy)
			{
				return;
			}
			if (!CanSell(store, out string reason))
			{
				if (reason.Length > 0)
				{
					Player localPlayer = Player.m_localPlayer;
					if (localPlayer != null)
					{
						((Character)localPlayer).Message((MessageType)2, reason, 0, (Sprite)null, false);
					}
				}
			}
			else
			{
				SellOffer val = selected;
				BeginSale(store, val.Sources.Cast<ItemData>().ToList(), ItemsPerSale(val), val.Price, TradeWorld.Item(val.Currency) ?? Currencies.Vanilla(), val.Prefab, val.Quality, val.Stack, vanilla: false);
			}
		}

		internal static bool CanSellValuables(StoreGui store, out string reason)
		{
			reason = string.Empty;
			Player localPlayer = Player.m_localPlayer;
			if (busy || (Object)(object)store == (Object)null || (Object)(object)store.m_trader == (Object)null || (Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (TradeAuthority.RecoveryBlocked || SafeTradeInventory.IsBlocked(inventory))
			{
				reason = TradeAuthority.UnavailableReason;
				return false;
			}
			if (OptionalTradeIntegrations.InventoryHeld(inventory))
			{
				reason = BarterText.Text("trade_inventory_held");
				return false;
			}
			ItemData sellableItem = store.GetSellableItem();
			ItemDrop val = store.m_coinPrefab ?? Currencies.Vanilla();
			if (sellableItem == null || (Object)(object)val == (Object)null || sellableItem.m_stack <= 0 || sellableItem.m_shared.m_value <= 0)
			{
				return false;
			}
			long num = (long)sellableItem.m_stack * (long)sellableItem.m_shared.m_value;
			if (num > int.MaxValue)
			{
				reason = TradeAuthority.UnavailableReason;
				return false;
			}
			if (!Purses.CanPay(store.m_trader, (int)num))
			{
				reason = BarterText.Format("sell_trader_poor", store.m_trader.GetHoverName());
				return false;
			}
			if (!CanReceivePayment(inventory, (IReadOnlyList<ItemData>)(object)new ItemData[1] { sellableItem }, sellableItem.m_stack, (int)num, val))
			{
				reason = BarterText.Text("sell_no_room");
				return false;
			}
			return true;
		}

		internal static void SellValuables(StoreGui store)
		{
			if (busy || (Object)(object)store == (Object)null || (Object)(object)store.m_trader == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			ItemData sellableItem = store.GetSellableItem();
			ItemDrop val = store.m_coinPrefab ?? Currencies.Vanilla();
			if (sellableItem != null && !((Object)(object)val == (Object)null) && sellableItem.m_stack > 0 && sellableItem.m_shared.m_value > 0)
			{
				long num = (long)sellableItem.m_stack * (long)sellableItem.m_shared.m_value;
				if (num <= int.MaxValue)
				{
					BeginSale(store, new List<ItemData> { sellableItem }, sellableItem.m_stack, (int)num, val, TradeWorld.PrefabName(sellableItem), sellableItem.m_quality, 1, vanilla: true);
				}
			}
		}

		private static void BeginSale(StoreGui store, List<ItemData> items, int needed, int price, ItemDrop currency, string prefab, int quality, int lotSize, bool vanilla)
		{
			Player player = Player.m_localPlayer;
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (OptionalTradeIntegrations.InventoryHeld(inventory))
			{
				((Character)player).Message((MessageType)2, BarterText.Text("trade_inventory_held"), 0, (Sprite)null, false);
				return;
			}
			if (TradeAuthority.RecoveryBlocked || SafeTradeInventory.IsBlocked(inventory))
			{
				((Character)player).Message((MessageType)2, TradeAuthority.UnavailableReason, 0, (Sprite)null, false);
				return;
			}
			Trader trader = store.m_trader;
			if ((Object)(object)currency == (Object)null || items.Count == 0 || needed <= 0 || price < 0)
			{
				return;
			}
			if (!CanReceivePayment(inventory, items, needed, price, currency))
			{
				((Character)player).Message((MessageType)2, BarterText.Text("sell_no_room"), 0, (Sprite)null, false);
				return;
			}
			TradeRequest request = new TradeRequest
			{
				Buy = false,
				Vanilla = vanilla,
				Prefab = prefab,
				Amount = needed,
				Quality = quality,
				Price = price,
				Currency = Utils.GetPrefabName(((Component)currency).gameObject),
				LotSize = lotSize
			};
			bool num = Plugin.Settings.GetFor<bool>(Services.BuybackEnabled, TradeWorld.TraderName(trader));
			if (num && !Plugin.Session.IsAuthority)
			{
				((Character)player).Message((MessageType)2, BarterText.Text("service_authority_only"), 0, (Sprite)null, false);
			}
			if (num && Plugin.Session.IsAuthority)
			{
				List<SafeTradeInventory.Take> list = new List<SafeTradeInventory.Take>();
				int num2 = needed;
				foreach (ItemData item in items)
				{
					int num3 = Math.Min(num2, item.m_stack);
					if (num3 > 0)
					{
						list.Add(new SafeTradeInventory.Take(item, num3));
					}
					num2 -= num3;
				}
				if (num2 != 0)
				{
					return;
				}
				try
				{
					request.Snapshot = TradeItemSnapshot.Encode(list);
				}
				catch (Exception ex)
				{
					MeadworksLog log = Plugin.Log;
					if (log != null)
					{
						log.Warning("Sale snapshot refused: " + ex.GetType().Name);
					}
					return;
				}
			}
			if (!TradeCodec.FitsReservation(request, Plugin.Session.SessionId))
			{
				((Character)player).Message((MessageType)2, BarterText.Text("sell_buyback_too_large"), 0, (Sprite)null, false);
				return;
			}
			int[] counts = items.Select((ItemData item) => item.m_stack).ToArray();
			busy = true;
			int attempt = ++pendingGeneration;
			if (!TradeAuthority.TryBegin(store, request, delegate(TradePermit permit)
			{
				//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (attempt != pendingGeneration)
					{
						permit?.Finish(success: false);
					}
					else if (permit == null)
					{
						((Character)player).Message((MessageType)2, TradeAuthority.UnavailableReason, 0, (Sprite)null, false);
					}
					else if (!permit.IsCurrent || (Object)(object)Player.m_localPlayer != (Object)(object)player || (Object)(object)store == (Object)null || (Object)(object)store.m_trader != (Object)(object)trader || ((Humanoid)player).GetInventory() != inventory || !StoreGui.IsVisible() || items.Where((ItemData item, int i) => !inventory.ContainsItem(item) || item.m_stack != counts[i] || item.m_equipped || OptionalTradeIntegrations.ProtectedItem(item, player) || item.m_quality != quality || TradeWorld.PrefabName(item) != prefab).Any())
					{
						permit.Finish(success: false);
					}
					else
					{
						List<SafeTradeInventory.Take> list2 = new List<SafeTradeInventory.Take>();
						int num4 = needed;
						foreach (ItemData item2 in items)
						{
							int num5 = Math.Min(num4, item2.m_stack);
							if (num5 <= 0)
							{
								break;
							}
							list2.Add(new SafeTradeInventory.Take(item2, num5));
							num4 -= num5;
						}
						if (num4 != 0)
						{
							permit.Finish(success: false);
						}
						else if (request.Snapshot.Length > 0 && TradeItemSnapshot.Encode(list2) != request.Snapshot)
						{
							permit.Finish(success: false);
						}
						else
						{
							ItemData output = SafeTradeInventory.Template(currency, currency.m_itemData.m_quality, list2.Any((SafeTradeInventory.Take take) => take.Item.m_cheated));
							ExchangeResult exchangeResult = SafeTradeInventory.Exchange(inventory, list2, output, price);
							if (exchangeResult == ExchangeResult.Unresolved)
							{
								MeadworksLog log2 = Plugin.Log;
								if (log2 != null)
								{
									log2.Warning("Trade inventory rollback could not be proven; the server reservation remains locked for recovery.");
								}
							}
							else
							{
								permit.Finish(exchangeResult == ExchangeResult.Completed);
								if (exchangeResult != ExchangeResult.Completed)
								{
									((Character)player).Message((MessageType)2, BarterText.Text((exchangeResult == ExchangeResult.InventoryHeld) ? "trade_inventory_held" : "sell_no_room"), 0, (Sprite)null, false);
								}
								else
								{
									string text = ((needed > 1) ? (needed + "x ") : string.Empty) + Localization.instance.Localize(items[0].m_shared.m_name);
									trader.OnSold();
									store.m_sellEffects.Create(((Component)store).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
									((Character)player).Message((MessageType)1, BarterText.Format("sell_sold", text, price, Currencies.Name(currency)), 0, items[0].m_shared.m_icons[0], false);
									Gogan.LogEvent("Game", "SoldItem", text, 0L);
								}
							}
						}
					}
				}
				finally
				{
					if (attempt == pendingGeneration)
					{
						busy = false;
					}
					if ((Object)(object)store != (Object)null && (Object)(object)store.m_trader == (Object)(object)trader && StoreGui.IsVisible())
					{
						store.FillList();
					}
				}
			}))
			{
				busy = false;
				((Character)player).Message((MessageType)2, TradeAuthority.UnavailableReason, 0, (Sprite)null, false);
			}
		}

		private static bool CanReceivePayment(Inventory inventory, IReadOnlyList<ItemData> items, int needed, int price, ItemDrop currency)
		{
			if ((Object)(object)currency == (Object)null || needed <= 0)
			{
				return false;
			}
			List<SafeTradeInventory.Take> list = new List<SafeTradeInventory.Take>();
			foreach (ItemData item in items)
			{
				if (item == null)
				{
					return false;
				}
				int num = Math.Min(needed, item.m_stack);
				if (num > 0)
				{
					list.Add(new SafeTradeInventory.Take(item, num));
				}
				needed -= num;
				if (needed == 0)
				{
					break;
				}
			}
			if (needed == 0)
			{
				return SafeTradeInventory.CanFitExchange(inventory, list, SafeTradeInventory.Template(currency, currency.m_itemData.m_quality, cheated: false), price);
			}
			return false;
		}

		private static bool SameCurrencyAsTrader(SellOffer offer, StoreGui store)
		{
			ItemDrop val = TradeWorld.Item(offer.Currency);
			ItemDrop val2 = (ItemDrop)(((Object)(object)store.m_coinPrefab != (Object)null) ? ((object)store.m_coinPrefab) : ((object)Currencies.Vanilla()));
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				return val.m_itemData.m_shared.m_name == val2.m_itemData.m_shared.m_name;
			}
			return true;
		}

		private static bool Same(SellOffer a, SellOffer b)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (a.Kind == b.Kind && a.Prefab == b.Prefab && a.Stack == b.Stack && a.Quality == b.Quality && a.Currency == b.Currency)
			{
				if ((int)a.Kind == 0)
				{
					return a.Sources[0] == b.Sources[0];
				}
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(EnvMan), "UpdateTriggers")]
	internal static class EnvMan_UpdateTriggers_Refill
	{
		private static bool IsMorning(float oldDayFraction, float newDayFraction)
		{
			if (oldDayFraction > 0.2f && oldDayFraction < 0.25f && newDayFraction >= 0.25f)
			{
				return newDayFraction < 0.3f;
			}
			return false;
		}

		private static void Postfix(float oldDayFraction, float newDayFraction)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Active || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || !IsMorning(oldDayFraction, newDayFraction))
			{
				return;
			}
			bool flag = Plugin.Log != null && Plugin.Log.IsEnabled((LogSeverity)4);
			int num = (flag ? Time.frameCount : 0);
			bool flag2 = false;
			if (flag)
			{
				RefillTiming.Begin();
			}
			try
			{
				if (Purses.Refill() && ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2]
					{
						1,
						BarterText.Token("purse_refilled")
					});
				}
				flag2 = true;
			}
			catch (Exception ex)
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning("Purse refill failed: " + ex.GetType().Name + ": " + ex.Message);
				}
			}
			finally
			{
				if (flag)
				{
					Result val = RefillTiming.End();
					try
					{
						Plugin.Log.Debug(FormattableString.Invariant($"stall-timing event=morning-refill frame={num} thread={Thread.CurrentThread.ManagedThreadId} old_fraction={oldDayFraction:R} new_fraction={newDayFraction:R} day={val.Day} backend={ZNet.World?.m_fileSource} completed={flag2} world_zdos={ZDOMan.instance?.m_objectsByID.Count ?? 0} scanned={val.Scanned} traders={val.Traders} refilled={val.Refilled} frequency={Stopwatch.Frequency} total_ticks={val.TotalTicks} scan_and_rules_ticks={val.TotalTicks - val.AuthorityRead.Ticks - val.AuthorityWrite.Ticks} auth_read_count={val.AuthorityRead.Count} auth_read_ticks={val.AuthorityRead.Ticks} auth_write_count={val.AuthorityWrite.Count} auth_write_ticks={val.AuthorityWrite.Ticks} local_read_count={val.LocalRead.Count} local_read_ticks={val.LocalRead.Ticks} local_write_count={val.LocalWrite.Count} local_write_ticks={val.LocalWrite.Ticks} cloud_read_count={val.CloudRead.Count} cloud_read_ticks={val.CloudRead.Ticks} cloud_write_count={val.CloudWrite.Count} cloud_write_ticks={val.CloudWrite.Ticks} promote_count={val.Promote.Count} promote_ticks={val.Promote.Ticks} flush_count={val.Flush.Count} flush_ticks={val.Flush.Ticks} cloud_finish_count={val.CloudFinish.Count} cloud_finish_ticks={val.CloudFinish.Ticks}"));
					}
					catch
					{
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
	internal static class Trader_GetAvailableItems_Lists
	{
		[HarmonyFinalizer]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception, Trader __instance, ref List<TradeItem> __result)
		{
			if (__exception != null || !Plugin.Active)
			{
				return __exception;
			}
			try
			{
				TradeOffers.Apply(__instance, ref __result);
			}
			catch (Exception ex)
			{
				MeadworksLog log = Plugin.Log;
				if (log != null)
				{
					log.Warning("Trader list failed for " + (((Object)(object)__instance != (Object)null) ? ((Object)__instance).name : "?") + ": " + ex.GetType().Name + ": " + ex.Message);
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(StoreGui), "Show")]
	internal static class StoreGui_Show_Barter
	{
		private static Trader before;

		private static void Prefix(StoreGui __instance, Trader trader)
		{
			before = (StoreGui.IsVisible() ? __instance.m_trader : null);
			if (Plugin.Active)
			{
				Currencies.Apply(__instance, trader);
			}
		}

		private static void Postfix(StoreGui __instance, Trader trader)
		{
			StoreUi.Shown(__instance);
			if (Plugin.Active)
			{
				StoreUi.Opened(__instance, before != trader);
			}
		}
	}
	[HarmonyPatch(typeof(StoreGui), "Hide")]
	internal static class StoreGui_Hide_Barter
	{
		private static void Postfix(StoreGui __instance)
		{
			Currencies.Restore(__instance);
			StoreUi.Closed(__instance);
		}
	}
	[HarmonyPatch(typeof(StoreGui), "Update")]
	internal static class StoreGui_Update_Barter
	{
		private static bool Prefix(StoreGui __instance)
		{
			if (Plugin.Active)
			{
				return !StoreUi.BeforeNativeUpdate(__instance);
			}
			return true;
		}

		private static void Postfix(StoreGui __instance)
		{
			StoreUi.Tick(__instance);
		}
	}
	[HarmonyPatch(typeof(StoreGui), "FillList")]
	internal static class StoreGui_FillList_Barter
	{
		private static void Postfix(StoreGui __instance)
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Active || (Object)(object)__instance.m_trader == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			List<TradeItem> availableItems = __instance.m_trader.GetAvailableItems();
			Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory();
			for (int i = 0; i < availableItems.Count && i < __instance.m_itemList.Count; i++)
			{
				GameObject val = __instance.m_itemList[i];
				OfferInfo offerInfo = TradeOffers.InfoOf(availableItems[i]);
				ItemDrop currency = TradeOffers.CurrencyOf(offerInfo, __instance);
				Currencies.SetIcons(val, currency);
				if (offerInfo == null || !offerInfo.FromList)
				{
					continue;
				}
				bool flag = availableItems[i].m_price <= Currencies.Count(inventory, currency);
				Transform obj = val.transform.Find("icon");
				Image val2 = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
				if ((Object)(object)val2 != (Object)null)
				{
					((Graphic)val2).color = (Color)(flag ? Color.white : new Color(1f, 0f, 1f, 0f));
				}
				Transform obj2 = val.transform.Find("name");
				TMP_Text val3 = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null);
				if ((Object)(object)val3 != (Object)null)
				{
					((Graphic)val3).color = (flag ? Color.white : Color.grey);
					if (offerInfo.Quality > 1)
					{
						val3.text = val3.text + " <color=#add8e6ff>(" + offerInfo.Quality + ")</color>";
					}
				}
				Transform obj3 = Utils.FindChild(val.transform, "price", (IterativeSearchType)0);
				TMP_Text val4 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
				if ((Object)(object)val4 != (Object)null)
				{
					((Graphic)val4).color = (flag ? Color.white : Color.grey);
				}
			}
			SellService.Refresh(__instance);
		}
	}
	[HarmonyPatch(typeof(StoreGui), "CanAfford")]
	internal static class StoreGui_CanAfford_Barter
	{
		private static bool Prefix(StoreGui __instance, TradeItem item, ref bool __result)
		{
			OfferInfo offerInfo = (Plugin.Active ? TradeOffers.InfoOf(item) : null);
			if (offerInfo == null || !offerInfo.FromList || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			__result = item.m_price <= Currencies.Count(((Humanoid)Player.m_localPlayer).GetInventory(), TradeOffers.CurrencyOf(offerInfo, __instance));
			return false;
		}
	}
	[HarmonyPatch(typeof(StoreGui), "BuySelectedItem")]
	internal static class StoreGui_BuySelectedItem_Barter
	{
		[HarmonyPrefix]
		private static void NotifyHeld(StoreGui __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			if (Plugin.Active && __instance.m_selectedItem != null && (Object)(object)localPlayer != (Object)null && OptionalTradeIntegrations.InventoryHeld(((Humanoid)localPlayer).GetInventory()))
			{
				((Character)localPlayer).Message((MessageType)2, BarterText.Text("trade_inventory_held"), 0, (Sprite)null, false);
			}
		}

		private static bool Prefix(StoreGui __instance)
		{
			TradeItem selectedItem = __instance.m_selectedItem;
			if (Plugin.AwaitingRules)
			{
				return false;
			}
			if (!Plugin.Active)
			{
				return true;
			}
			if (selectedItem == null)
			{
				return false;
			}
			OfferInfo info = TradeOffers.InfoOf(selectedItem);
			if (__instance.CanAfford(selectedItem))
			{
				BuyService.Buy(__instance, selectedItem, info);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(StoreGui), "GetSelectedItemIndex")]
	internal static class StoreGui_GetSelectedItemIndex_Barter
	{
		private static void Postfix(StoreGui __instance, ref int __result)
		{
			TradeItem selectedItem = __instance.m_selectedItem;
			if (!Plugin.Active || selectedItem == null || (Object)(object)__instance.m_trader == (Object)null)
			{
				return;
			}
			List<TradeItem> availableItems = __instance.m_trader.GetAvailableItems();
			if (__result >= 0 && __result < availableItems.Count && availableItems[__result] == selectedItem)
			{
				return;
			}
			object obj = TradeOffers.OriginOf(selectedItem);
			for (int i = 0; i < availableItems.Count; i++)
			{
				if (TradeOffers.OriginOf(availableItems[i]) == obj)
				{
					__result = i;
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(StoreGui), "UpdateSellButton")]
	internal static class StoreGui_UpdateSellButton_Barter
	{
		internal static bool Takeover
		{
			get
			{
				if (Plugin.Active && TradeLists.Ready)
				{
					return StoreUi.SellPanelAllowed;
				}
				return false;
			}
		}

		private static bool Prefix(StoreGui __instance)
		{
			string reason;
			if (!Takeover)
			{
				if (!Plugin.Active)
				{
					return true;
				}
				((Selectable)__instance.m_sellButton).interactable = SellService.CanSellValuables(__instance, out reason);
				return false;
			}
			((Selectable)__instance.m_sellButton).interactable = SellService.CanSell(__instance, out reason);
			return false;
		}
	}
	[HarmonyPatch(typeof(StoreGui), "SellItem")]
	internal static class StoreGui_SellItem_Barter
	{
		private static bool Prefix(StoreGui __instance)
		{
			if (Plugin.AwaitingRules)
			{
				return false;
			}
			if (!Plugin.Active)
			{
				return true;
			}
			if (StoreGui_UpdateSellButton_Barter.Takeover)
			{
				SellService.Sell(__instance);
			}
			else
			{
				SellService.SellValuables(__instance);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Inventory), "Changed")]
	internal static class Inventory_Changed_Barter
	{
		[HarmonyPriority(800)]
		private static void Prefix(Inventory __instance)
		{
			SafeTradeInventory.ObserveBeforeChanged(__instance);
		}

		private static void Postfix(Inventory __instance)
		{
			if (__instance != null && !__instance.m_temoraryInventory && (Object)(object)Player.m_localPlayer != (Object)null && __instance == ((Humanoid)Player.m_localPlayer).GetInventory())
			{
				StoreUi.InventoryChanged();
			}
		}
	}
	internal sealed class TradePermit
	{
		private readonly TradeRequest request;

		private readonly long generation;

		private bool finished;

		internal bool IsCurrent
		{
			get
			{
				if (!finished && Plugin.Active && Plugin.IsReady && Plugin.Session.AuthorityReady)
				{
					return Plugin.Session.Generation == generation;
				}
				return false;
			}
		}

		internal TradePermit(TradeRequest request, long generation)
		{
			this.request = request;
			this.generation = generation;
		}

		internal void Finish(bool success)
		{
			if (!finished)
			{
				finished = true;
				TradeAuthority.Finish(request, success);
			}
		}
	}
	internal static class TradeAuthority
	{
		private sealed class Recovery
		{
			internal TradeRequest Request;

			internal TradeRecovery State;

			internal JournalEntry Journal;

			internal bool Reopened;

			internal bool CharacterSaved;
		}

		private struct ReceiptMarker
		{
			internal string Key;

			internal string Epoch;

			internal long World;

			internal long Sequence;

			internal int Day;

			internal bool JournalOpen;
		}

		private const string ReserveOperation = "meadworks.barter.reserve";

		private const string FinishOperation = "meadworks.barter.finish";

		private static readonly List<Action> observations = new List<Action>();

		private static readonly List<IDisposable> registrations = new List<IDisposable>();

		private static readonly Dictionary<string, bool> localEvidence = new Dictionary<string, bool>(StringComparer.Ordinal);

		private static Player loadedPlayer;

		private static readonly HashSet<string> loadedMarkers = new HashSet<string>(StringComparer.Ordinal);

		internal const int MaxRetiredReceiptMarkers = 64;

		private const string MarkerPrefix = "meadworks.barter.receipt.";

		private static long nextMarkerSequence = 1L;

		private static string prunedSession = "";

		private static bool pruneSaveFailed;

		private static readonly Dictionary<string, Recovery> outcomes = new Dictionary<string, Recovery>(StringComparer.Ordinal);

		private static readonly TradeJournal journal = new TradeJournal(Path.Combine(Paths.ConfigPath, "Barter.Recovery"));

		private static bool journalLoaded;

		private static bool journalFailed;

		private static readonly Stopwatch clock = Stopwatch.StartNew();

		private static bool recovering;

		internal static bool RecoveryBlocked => RecoveryStatus.Length > 0;

		internal static string UnavailableReason
		{
			get
			{
				string recoveryStatus = RecoveryStatus;
				if (recoveryStatus.Length <= 0)
				{
					return BarterText.Text("trade_unavailable");
				}
				return recoveryStatus;
			}
		}

		internal static string RecoveryStatus
		{
			get
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null || !Plugin.IsReady)
				{
					return "";
				}
				string text = Path.Combine(Paths.ConfigPath, "Barter.Recovery");
				if (journalFailed)
				{
					return BarterText.Format("trade_recovery_unreadable", text);
				}
				string text2 = Player.m_localPlayer.GetPlayerID().ToString(CultureInfo.InvariantCulture);
				foreach (Recovery value in outcomes.Values)
				{
					if (value.Journal.World == Plugin.Session.WorldId && value.Journal.Actor == text2 && !value.State.Outcome.HasValue)
					{
						return BarterText.Format("trade_recovery_pending", value.Request.Token, text);
					}
				}
				return "";
			}
		}

		internal static bool RecoveryInFlight => recovering;

		private static string Marker(string token)
		{
			return "meadworks.barter.receipt." + Plugin.Session.WorldId.ToString(CultureInfo.InvariantCulture) + ":" + token;
		}

		private static int CurrentDay()
		{
			if (!((Object)(object)EnvMan.instance == (Object)null))
			{
				return EnvMan.instance.GetCurrentDay();
			}
			return -1;
		}

		private static bool CurrentSession(out string session)
		{
			session = "";
			if (!Plugin.IsReady || !Plugin.Session.AuthorityReady)
			{
				return false;
			}
			session = Plugin.Session.SessionId ?? "";
			return session.Length > 0;
		}

		private static string FormatMarker(Player player, TradeRequest request)
		{
			long num = nextMarkerSequence;
			if ((Object)(object)player != (Object)null)
			{
				foreach (KeyValuePair<string, string> customDatum in player.m_customData)
				{
					if (TryParseMarkerKey(customDatum.Key, out long _, out string token) && TryParseMarkerValue(customDatum.Value, out token, out long sequence, out int _, out string _) && sequence >= num)
					{
						num = sequence + 1;
					}
				}
			}
			nextMarkerSequence = num + 1;
			string session;
			string text = (CurrentSession(out session) ? session : "");
			return "2:" + TradeCodec.Fingerprint(request) + "|" + num.ToString(CultureInfo.InvariantCulture) + "|" + CurrentDay().ToString(CultureInfo.InvariantCulture) + "|" + text;
		}

		private static bool TryParseMarkerKey(string key, out long world, out string token)
		{
			world = 0L;
			token = "";
			if (key == null || !key.StartsWith("meadworks.barter.receipt.", StringComparison.Ordinal))
			{
				return false;
			}
			string text = key.Substring("meadworks.barter.receipt.".Length);
			int num = text.IndexOf(':');
			if (num <= 0 || !long.TryParse(text.Substring(0, num), NumberStyles.Integer, CultureInfo.InvariantCulture, out world))
			{

plugins/Barter/YamlDotNet.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.CodeAnalysis;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("13.7.1.0")]
[assembly: AssemblyInformationalVersion("13.7.1")]
[assembly: AssemblyTitle("YamlDotNet")]
[assembly: AssemblyDescription("The YamlDotNet library.")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("YamlDotNet")]
[assembly: AssemblyCopyright("Copyright (c) Antoine Aubry and contributors 2008 - 2019")]
[assembly: AssemblyTrademark("")]
[assembly: CLSCompliant(true)]
[assembly: InternalsVisibleTo("YamlDotNet.Test, PublicKey=002400000480000094000000060200000024000052534131000400000100010065e52a453dde5c5b4be5bbe2205755727fce80244b79b894faf8793d80f7db9a96d360b51c220782db32aacee4cb5b8a91bee33aeec700e1f21895c4baadef501eeeac609220d1651603b378173811ee5bb6a002df973d38821bd2fef820c00c174a69faec326a1983b570f07ec66147026b9c8753465de3a8d0c44b613b02af")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("13.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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 YamlDotNet
{
	internal sealed class CultureInfoAdapter : CultureInfo
	{
		private readonly IFormatProvider provider;

		public CultureInfoAdapter(CultureInfo baseCulture, IFormatProvider provider)
			: base(baseCulture.Name)
		{
			this.provider = provider;
		}

		public override object GetFormat(Type formatType)
		{
			return provider.GetFormat(formatType);
		}
	}
	internal static class ReflectionExtensions
	{
		private static readonly Func<PropertyInfo, bool> IsInstance = (PropertyInfo property) => !(property.GetMethod ?? property.SetMethod).IsStatic;

		private static readonly Func<PropertyInfo, bool> IsInstancePublic = (PropertyInfo property) => IsInstance(property) && (property.GetMethod ?? property.SetMethod).IsPublic;

		public static Type? BaseType(this Type type)
		{
			return type.GetTypeInfo().BaseType;
		}

		public static bool IsValueType(this Type type)
		{
			return type.GetTypeInfo().IsValueType;
		}

		public static bool IsGenericType(this Type type)
		{
			return type.GetTypeInfo().IsGenericType;
		}

		public static bool IsGenericTypeDefinition(this Type type)
		{
			return type.GetTypeInfo().IsGenericTypeDefinition;
		}

		public static bool IsInterface(this Type type)
		{
			return type.GetTypeInfo().IsInterface;
		}

		public static bool IsEnum(this Type type)
		{
			return type.GetTypeInfo().IsEnum;
		}

		public static bool HasDefaultConstructor(this Type type, bool allowPrivateConstructors)
		{
			TypeInfo typeInfo = type.GetTypeInfo();
			if (!typeInfo.IsValueType)
			{
				return typeInfo.DeclaredConstructors.Any((ConstructorInfo c) => (c.IsPublic || (allowPrivateConstructors && c.IsPrivate)) && !c.IsStatic && c.GetParameters().Length == 0);
			}
			return true;
		}

		public static bool IsAssignableFrom(this Type type, Type source)
		{
			return type.IsAssignableFrom(source.GetTypeInfo());
		}

		public static bool IsAssignableFrom(this Type type, TypeInfo source)
		{
			return type.GetTypeInfo().IsAssignableFrom(source);
		}

		public static TypeCode GetTypeCode(this Type type)
		{
			if (type.IsEnum())
			{
				type = Enum.GetUnderlyingType(type);
			}
			if (type == typeof(bool))
			{
				return TypeCode.Boolean;
			}
			if (type == typeof(char))
			{
				return TypeCode.Char;
			}
			if (type == typeof(sbyte))
			{
				return TypeCode.SByte;
			}
			if (type == typeof(byte))
			{
				return TypeCode.Byte;
			}
			if (type == typeof(short))
			{
				return TypeCode.Int16;
			}
			if (type == typeof(ushort))
			{
				return TypeCode.UInt16;
			}
			if (type == typeof(int))
			{
				return TypeCode.Int32;
			}
			if (type == typeof(uint))
			{
				return TypeCode.UInt32;
			}
			if (type == typeof(long))
			{
				return TypeCode.Int64;
			}
			if (type == typeof(ulong))
			{
				return TypeCode.UInt64;
			}
			if (type == typeof(float))
			{
				return TypeCode.Single;
			}
			if (type == typeof(double))
			{
				return TypeCode.Double;
			}
			if (type == typeof(decimal))
			{
				return TypeCode.Decimal;
			}
			if (type == typeof(DateTime))
			{
				return TypeCode.DateTime;
			}
			if (type == typeof(string))
			{
				return TypeCode.String;
			}
			return TypeCode.Object;
		}

		public static bool IsDbNull(this object value)
		{
			return value?.GetType()?.FullName == "System.DBNull";
		}

		public static Type[] GetGenericArguments(this Type type)
		{
			return type.GetTypeInfo().GenericTypeArguments;
		}

		public static PropertyInfo? GetPublicProperty(this Type type, string name)
		{
			return type.GetRuntimeProperty(name);
		}

		public static FieldInfo? GetPublicStaticField(this Type type, string name)
		{
			return type.GetRuntimeField(name);
		}

		public static IEnumerable<PropertyInfo> GetProperties(this Type type, bool includeNonPublic)
		{
			Func<PropertyInfo, bool> predicate = (includeNonPublic ? IsInstance : IsInstancePublic);
			if (!type.IsInterface())
			{
				return type.GetRuntimeProperties().Where(predicate);
			}
			return new Type[1] { type }.Concat(type.GetInterfaces()).SelectMany((Type i) => i.GetRuntimeProperties().Where(predicate));
		}

		public static IEnumerable<PropertyInfo> GetPublicProperties(this Type type)
		{
			return type.GetProperties(includeNonPublic: false);
		}

		public static IEnumerable<FieldInfo> GetPublicFields(this Type type)
		{
			return from f in type.GetRuntimeFields()
				where !f.IsStatic && f.IsPublic
				select f;
		}

		public static IEnumerable<MethodInfo> GetPublicStaticMethods(this Type type)
		{
			return from m in type.GetRuntimeMethods()
				where m.IsPublic && m.IsStatic
				select m;
		}

		public static MethodInfo GetPrivateStaticMethod(this Type type, string name)
		{
			return type.GetRuntimeMethods().FirstOrDefault((MethodInfo m) => !m.IsPublic && m.IsStatic && m.Name.Equals(name)) ?? throw new MissingMethodException("Expected to find a method named '" + name + "' in '" + type.FullName + "'.");
		}

		public static MethodInfo? GetPublicStaticMethod(this Type type, string name, params Type[] parameterTypes)
		{
			return type.GetRuntimeMethods().FirstOrDefault(delegate(MethodInfo m)
			{
				if (m.IsPublic && m.IsStatic && m.Name.Equals(name))
				{
					ParameterInfo[] parameters = m.GetParameters();
					if (parameters.Length == parameterTypes.Length)
					{
						return parameters.Zip(parameterTypes, (ParameterInfo pi, Type pt) => pi.ParameterType == pt).All((bool r) => r);
					}
					return false;
				}
				return false;
			});
		}

		public static MethodInfo? GetPublicInstanceMethod(this Type type, string name)
		{
			return type.GetRuntimeMethods().FirstOrDefault((MethodInfo m) => m.IsPublic && !m.IsStatic && m.Name.Equals(name));
		}

		public static MethodInfo? GetGetMethod(this PropertyInfo property, bool nonPublic)
		{
			MethodInfo methodInfo = property.GetMethod;
			if (!nonPublic && !methodInfo.IsPublic)
			{
				methodInfo = null;
			}
			return methodInfo;
		}

		public static MethodInfo GetSetMethod(this PropertyInfo property)
		{
			return property.SetMethod;
		}

		public static IEnumerable<Type> GetInterfaces(this Type type)
		{
			return type.GetTypeInfo().ImplementedInterfaces;
		}

		public static Exception Unwrap(this TargetInvocationException ex)
		{
			return ex.InnerException;
		}

		public static bool IsInstanceOf(this Type type, object o)
		{
			if (!(o.GetType() == type))
			{
				return o.GetType().GetTypeInfo().IsSubclassOf(type);
			}
			return true;
		}

		public static Attribute[] GetAllCustomAttributes<TAttribute>(this PropertyInfo member)
		{
			List<Attribute> list = new List<Attribute>();
			Type type = member.DeclaringType;
			while (type != null)
			{
				type.GetPublicProperty(member.Name);
				list.AddRange(member.GetCustomAttributes(typeof(TAttribute)));
				type = type.BaseType();
			}
			return list.ToArray();
		}
	}
	internal static class PropertyInfoExtensions
	{
		public static object? ReadValue(this PropertyInfo property, object target)
		{
			return property.GetValue(target, null);
		}
	}
	internal static class StandardRegexOptions
	{
		public const RegexOptions Compiled = RegexOptions.Compiled;
	}
}
namespace YamlDotNet.Serialization
{
	public abstract class BuilderSkeleton<TBuilder> where TBuilder : BuilderSkeleton<TBuilder>
	{
		internal INamingConvention namingConvention = NullNamingConvention.Instance;

		internal ITypeResolver typeResolver;

		internal readonly YamlAttributeOverrides overrides;

		internal readonly LazyComponentRegistrationList<Nothing, IYamlTypeConverter> typeConverterFactories;

		internal readonly LazyComponentRegistrationList<ITypeInspector, ITypeInspector> typeInspectorFactories;

		internal bool ignoreFields;

		internal bool includeNonPublicProperties;

		internal Settings settings;

		internal YamlFormatter yamlFormatter = YamlFormatter.Default;

		protected abstract TBuilder Self { get; }

		internal BuilderSkeleton(ITypeResolver typeResolver)
		{
			overrides = new YamlAttributeOverrides();
			typeConverterFactories = new LazyComponentRegistrationList<Nothing, IYamlTypeConverter>
			{
				{
					typeof(YamlDotNet.Serialization.Converters.GuidConverter),
					(Nothing _) => new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: false)
				},
				{
					typeof(SystemTypeConverter),
					(Nothing _) => new SystemTypeConverter()
				}
			};
			typeInspectorFactories = new LazyComponentRegistrationList<ITypeInspector, ITypeInspector>();
			this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver");
			settings = new Settings();
		}

		public TBuilder IgnoreFields()
		{
			ignoreFields = true;
			return Self;
		}

		public TBuilder IncludeNonPublicProperties()
		{
			includeNonPublicProperties = true;
			return Self;
		}

		public TBuilder EnablePrivateConstructors()
		{
			settings.AllowPrivateConstructors = true;
			return Self;
		}

		public TBuilder WithNamingConvention(INamingConvention namingConvention)
		{
			this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention");
			return Self;
		}

		public TBuilder WithTypeResolver(ITypeResolver typeResolver)
		{
			this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver");
			return Self;
		}

		public abstract TBuilder WithTagMapping(TagName tag, Type type);

		public TBuilder WithAttributeOverride<TClass>(Expression<Func<TClass, object>> propertyAccessor, Attribute attribute)
		{
			overrides.Add(propertyAccessor, attribute);
			return Self;
		}

		public TBuilder WithAttributeOverride(Type type, string member, Attribute attribute)
		{
			overrides.Add(type, member, attribute);
			return Self;
		}

		public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter)
		{
			return WithTypeConverter(typeConverter, delegate(IRegistrationLocationSelectionSyntax<IYamlTypeConverter> w)
			{
				w.OnTop();
			});
		}

		public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter, Action<IRegistrationLocationSelectionSyntax<IYamlTypeConverter>> where)
		{
			if (typeConverter == null)
			{
				throw new ArgumentNullException("typeConverter");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeConverterFactories.CreateRegistrationLocationSelector(typeConverter.GetType(), (Nothing _) => typeConverter));
			return Self;
		}

		public TBuilder WithTypeConverter<TYamlTypeConverter>(WrapperFactory<IYamlTypeConverter, IYamlTypeConverter> typeConverterFactory, Action<ITrackingRegistrationLocationSelectionSyntax<IYamlTypeConverter>> where) where TYamlTypeConverter : IYamlTypeConverter
		{
			if (typeConverterFactory == null)
			{
				throw new ArgumentNullException("typeConverterFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeConverterFactories.CreateTrackingRegistrationLocationSelector(typeof(TYamlTypeConverter), (IYamlTypeConverter wrapped, Nothing _) => typeConverterFactory(wrapped)));
			return Self;
		}

		public TBuilder WithoutTypeConverter<TYamlTypeConverter>() where TYamlTypeConverter : IYamlTypeConverter
		{
			return WithoutTypeConverter(typeof(TYamlTypeConverter));
		}

		public TBuilder WithoutTypeConverter(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			typeConverterFactories.Remove(converterType);
			return Self;
		}

		public TBuilder WithTypeInspector<TTypeInspector>(Func<ITypeInspector, TTypeInspector> typeInspectorFactory) where TTypeInspector : ITypeInspector
		{
			return WithTypeInspector(typeInspectorFactory, delegate(IRegistrationLocationSelectionSyntax<ITypeInspector> w)
			{
				w.OnTop();
			});
		}

		public TBuilder WithTypeInspector<TTypeInspector>(Func<ITypeInspector, TTypeInspector> typeInspectorFactory, Action<IRegistrationLocationSelectionSyntax<ITypeInspector>> where) where TTypeInspector : ITypeInspector
		{
			if (typeInspectorFactory == null)
			{
				throw new ArgumentNullException("typeInspectorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeInspectorFactories.CreateRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector inner) => typeInspectorFactory(inner)));
			return Self;
		}

		public TBuilder WithTypeInspector<TTypeInspector>(WrapperFactory<ITypeInspector, ITypeInspector, TTypeInspector> typeInspectorFactory, Action<ITrackingRegistrationLocationSelectionSyntax<ITypeInspector>> where) where TTypeInspector : ITypeInspector
		{
			if (typeInspectorFactory == null)
			{
				throw new ArgumentNullException("typeInspectorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeInspectorFactories.CreateTrackingRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector wrapped, ITypeInspector inner) => typeInspectorFactory(wrapped, inner)));
			return Self;
		}

		public TBuilder WithoutTypeInspector<TTypeInspector>() where TTypeInspector : ITypeInspector
		{
			return WithoutTypeInspector(typeof(TTypeInspector));
		}

		public TBuilder WithoutTypeInspector(Type inspectorType)
		{
			if (inspectorType == null)
			{
				throw new ArgumentNullException("inspectorType");
			}
			typeInspectorFactories.Remove(inspectorType);
			return Self;
		}

		public TBuilder WithYamlFormatter(YamlFormatter formatter)
		{
			yamlFormatter = formatter ?? throw new ArgumentNullException("formatter");
			return Self;
		}

		protected IEnumerable<IYamlTypeConverter> BuildTypeConverters()
		{
			return typeConverterFactories.BuildComponentList();
		}
	}
	public delegate TComponent WrapperFactory<TComponentBase, TComponent>(TComponentBase wrapped) where TComponent : TComponentBase;
	public delegate TComponent WrapperFactory<TArgument, TComponentBase, TComponent>(TComponentBase wrapped, TArgument argument) where TComponent : TComponentBase;
	[Flags]
	public enum DefaultValuesHandling
	{
		Preserve = 0,
		OmitNull = 1,
		OmitDefaults = 2,
		OmitEmptyCollections = 4
	}
	public sealed class Deserializer : IDeserializer
	{
		private readonly IValueDeserializer valueDeserializer;

		public Deserializer()
			: this(new DeserializerBuilder().BuildValueDeserializer())
		{
		}

		private Deserializer(IValueDeserializer valueDeserializer)
		{
			this.valueDeserializer = valueDeserializer ?? throw new ArgumentNullException("valueDeserializer");
		}

		public static Deserializer FromValueDeserializer(IValueDeserializer valueDeserializer)
		{
			return new Deserializer(valueDeserializer);
		}

		public T Deserialize<T>(string input)
		{
			using StringReader input2 = new StringReader(input);
			return Deserialize<T>(input2);
		}

		public T Deserialize<T>(TextReader input)
		{
			return Deserialize<T>(new Parser(input));
		}

		public T Deserialize<T>(IParser parser)
		{
			return (T)Deserialize(parser, typeof(T));
		}

		public object? Deserialize(string input)
		{
			return Deserialize(input, typeof(object));
		}

		public object? Deserialize(TextReader input)
		{
			return Deserialize(input, typeof(object));
		}

		public object? Deserialize(IParser parser)
		{
			return Deserialize(parser, typeof(object));
		}

		public object? Deserialize(string input, Type type)
		{
			using StringReader input2 = new StringReader(input);
			return Deserialize(input2, type);
		}

		public object? Deserialize(TextReader input, Type type)
		{
			return Deserialize(new Parser(input), type);
		}

		public object? Deserialize(IParser parser, Type type)
		{
			if (parser == null)
			{
				throw new ArgumentNullException("parser");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			YamlDotNet.Core.Events.StreamStart @event;
			bool flag = parser.TryConsume<YamlDotNet.Core.Events.StreamStart>(out @event);
			YamlDotNet.Core.Events.DocumentStart event2;
			bool flag2 = parser.TryConsume<YamlDotNet.Core.Events.DocumentStart>(out event2);
			object result = null;
			if (!parser.Accept<YamlDotNet.Core.Events.DocumentEnd>(out var _) && !parser.Accept<YamlDotNet.Core.Events.StreamEnd>(out var _))
			{
				using SerializerState serializerState = new SerializerState();
				result = valueDeserializer.DeserializeValue(parser, type, serializerState, valueDeserializer);
				serializerState.OnDeserialization();
			}
			if (flag2)
			{
				parser.Consume<YamlDotNet.Core.Events.DocumentEnd>();
			}
			if (flag)
			{
				parser.Consume<YamlDotNet.Core.Events.StreamEnd>();
			}
			return result;
		}
	}
	public sealed class DeserializerBuilder : BuilderSkeleton<DeserializerBuilder>
	{
		private Lazy<IObjectFactory> objectFactory;

		private readonly LazyComponentRegistrationList<Nothing, INodeDeserializer> nodeDeserializerFactories;

		private readonly LazyComponentRegistrationList<Nothing, INodeTypeResolver> nodeTypeResolverFactories;

		private readonly Dictionary<TagName, Type> tagMappings;

		private readonly Dictionary<Type, Type> typeMappings;

		private readonly ITypeConverter typeConverter;

		private bool ignoreUnmatched;

		private bool duplicateKeyChecking;

		private bool attemptUnknownTypeDeserialization;

		protected override DeserializerBuilder Self => this;

		public DeserializerBuilder()
			: base((ITypeResolver)new StaticTypeResolver())
		{
			typeMappings = new Dictionary<Type, Type>();
			objectFactory = new Lazy<IObjectFactory>(() => new DefaultObjectFactory(typeMappings, settings), isThreadSafe: true);
			tagMappings = new Dictionary<TagName, Type>
			{
				{
					FailsafeSchema.Tags.Map,
					typeof(Dictionary<object, object>)
				},
				{
					FailsafeSchema.Tags.Str,
					typeof(string)
				},
				{
					JsonSchema.Tags.Bool,
					typeof(bool)
				},
				{
					JsonSchema.Tags.Float,
					typeof(double)
				},
				{
					JsonSchema.Tags.Int,
					typeof(int)
				},
				{
					DefaultSchema.Tags.Timestamp,
					typeof(DateTime)
				}
			};
			typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner));
			typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner);
			typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner));
			typeInspectorFactories.Add(typeof(YamlAttributeOverridesInspector), (ITypeInspector inner) => (overrides == null) ? inner : new YamlAttributeOverridesInspector(inner, overrides.Clone()));
			typeInspectorFactories.Add(typeof(ReadableAndWritablePropertiesTypeInspector), (ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner));
			nodeDeserializerFactories = new LazyComponentRegistrationList<Nothing, INodeDeserializer>
			{
				{
					typeof(YamlConvertibleNodeDeserializer),
					(Nothing _) => new YamlConvertibleNodeDeserializer(objectFactory.Value)
				},
				{
					typeof(YamlSerializableNodeDeserializer),
					(Nothing _) => new YamlSerializableNodeDeserializer(objectFactory.Value)
				},
				{
					typeof(TypeConverterNodeDeserializer),
					(Nothing _) => new TypeConverterNodeDeserializer(BuildTypeConverters())
				},
				{
					typeof(NullNodeDeserializer),
					(Nothing _) => new NullNodeDeserializer()
				},
				{
					typeof(ScalarNodeDeserializer),
					(Nothing _) => new ScalarNodeDeserializer(attemptUnknownTypeDeserialization, typeConverter, yamlFormatter)
				},
				{
					typeof(ArrayNodeDeserializer),
					(Nothing _) => new ArrayNodeDeserializer()
				},
				{
					typeof(DictionaryNodeDeserializer),
					(Nothing _) => new DictionaryNodeDeserializer(objectFactory.Value, duplicateKeyChecking)
				},
				{
					typeof(CollectionNodeDeserializer),
					(Nothing _) => new CollectionNodeDeserializer(objectFactory.Value)
				},
				{
					typeof(EnumerableNodeDeserializer),
					(Nothing _) => new EnumerableNodeDeserializer()
				},
				{
					typeof(ObjectNodeDeserializer),
					(Nothing _) => new ObjectNodeDeserializer(objectFactory.Value, BuildTypeInspector(), ignoreUnmatched, duplicateKeyChecking, typeConverter)
				}
			};
			nodeTypeResolverFactories = new LazyComponentRegistrationList<Nothing, INodeTypeResolver>
			{
				{
					typeof(MappingNodeTypeResolver),
					(Nothing _) => new MappingNodeTypeResolver(typeMappings)
				},
				{
					typeof(YamlConvertibleTypeResolver),
					(Nothing _) => new YamlConvertibleTypeResolver()
				},
				{
					typeof(YamlSerializableTypeResolver),
					(Nothing _) => new YamlSerializableTypeResolver()
				},
				{
					typeof(TagNodeTypeResolver),
					(Nothing _) => new TagNodeTypeResolver(tagMappings)
				},
				{
					typeof(PreventUnknownTagsNodeTypeResolver),
					(Nothing _) => new PreventUnknownTagsNodeTypeResolver()
				},
				{
					typeof(DefaultContainersNodeTypeResolver),
					(Nothing _) => new DefaultContainersNodeTypeResolver()
				}
			};
			typeConverter = new ReflectionTypeConverter();
		}

		internal ITypeInspector BuildTypeInspector()
		{
			ITypeInspector typeInspector = new WritablePropertiesTypeInspector(typeResolver, includeNonPublicProperties);
			if (!ignoreFields)
			{
				typeInspector = new CompositeTypeInspector(new ReadableFieldsTypeInspector(typeResolver), typeInspector);
			}
			return typeInspectorFactories.BuildComponentChain(typeInspector);
		}

		public DeserializerBuilder WithAttemptingUnquotedStringTypeDeserialization()
		{
			attemptUnknownTypeDeserialization = true;
			return this;
		}

		public DeserializerBuilder WithObjectFactory(IObjectFactory objectFactory)
		{
			if (objectFactory == null)
			{
				throw new ArgumentNullException("objectFactory");
			}
			this.objectFactory = new Lazy<IObjectFactory>(() => objectFactory, isThreadSafe: true);
			return this;
		}

		public DeserializerBuilder WithObjectFactory(Func<Type, object> objectFactory)
		{
			if (objectFactory == null)
			{
				throw new ArgumentNullException("objectFactory");
			}
			return WithObjectFactory(new LambdaObjectFactory(objectFactory));
		}

		public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer)
		{
			return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax<INodeDeserializer> w)
			{
				w.OnTop();
			});
		}

		public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer, Action<IRegistrationLocationSelectionSyntax<INodeDeserializer>> where)
		{
			if (nodeDeserializer == null)
			{
				throw new ArgumentNullException("nodeDeserializer");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeDeserializerFactories.CreateRegistrationLocationSelector(nodeDeserializer.GetType(), (Nothing _) => nodeDeserializer));
			return this;
		}

		public DeserializerBuilder WithNodeDeserializer<TNodeDeserializer>(WrapperFactory<INodeDeserializer, TNodeDeserializer> nodeDeserializerFactory, Action<ITrackingRegistrationLocationSelectionSyntax<INodeDeserializer>> where) where TNodeDeserializer : INodeDeserializer
		{
			if (nodeDeserializerFactory == null)
			{
				throw new ArgumentNullException("nodeDeserializerFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeDeserializerFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeDeserializer), (INodeDeserializer wrapped, Nothing _) => nodeDeserializerFactory(wrapped)));
			return this;
		}

		public DeserializerBuilder WithoutNodeDeserializer<TNodeDeserializer>() where TNodeDeserializer : INodeDeserializer
		{
			return WithoutNodeDeserializer(typeof(TNodeDeserializer));
		}

		public DeserializerBuilder WithoutNodeDeserializer(Type nodeDeserializerType)
		{
			if (nodeDeserializerType == null)
			{
				throw new ArgumentNullException("nodeDeserializerType");
			}
			nodeDeserializerFactories.Remove(nodeDeserializerType);
			return this;
		}

		public DeserializerBuilder WithTypeDiscriminatingNodeDeserializer(Action<ITypeDiscriminatingNodeDeserializerOptions> configureTypeDiscriminatingNodeDeserializerOptions, int maxDepth = -1, int maxLength = -1)
		{
			TypeDiscriminatingNodeDeserializerOptions typeDiscriminatingNodeDeserializerOptions = new TypeDiscriminatingNodeDeserializerOptions();
			configureTypeDiscriminatingNodeDeserializerOptions(typeDiscriminatingNodeDeserializerOptions);
			TypeDiscriminatingNodeDeserializer nodeDeserializer = new TypeDiscriminatingNodeDeserializer(nodeDeserializerFactories.BuildComponentList(), typeDiscriminatingNodeDeserializerOptions.discriminators, maxDepth, maxLength);
			return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax<INodeDeserializer> s)
			{
				s.Before<DictionaryNodeDeserializer>();
			});
		}

		public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver)
		{
			return WithNodeTypeResolver(nodeTypeResolver, delegate(IRegistrationLocationSelectionSyntax<INodeTypeResolver> w)
			{
				w.OnTop();
			});
		}

		public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver, Action<IRegistrationLocationSelectionSyntax<INodeTypeResolver>> where)
		{
			if (nodeTypeResolver == null)
			{
				throw new ArgumentNullException("nodeTypeResolver");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeTypeResolverFactories.CreateRegistrationLocationSelector(nodeTypeResolver.GetType(), (Nothing _) => nodeTypeResolver));
			return this;
		}

		public DeserializerBuilder WithNodeTypeResolver<TNodeTypeResolver>(WrapperFactory<INodeTypeResolver, TNodeTypeResolver> nodeTypeResolverFactory, Action<ITrackingRegistrationLocationSelectionSyntax<INodeTypeResolver>> where) where TNodeTypeResolver : INodeTypeResolver
		{
			if (nodeTypeResolverFactory == null)
			{
				throw new ArgumentNullException("nodeTypeResolverFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeTypeResolverFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeTypeResolver), (INodeTypeResolver wrapped, Nothing _) => nodeTypeResolverFactory(wrapped)));
			return this;
		}

		public DeserializerBuilder WithoutNodeTypeResolver<TNodeTypeResolver>() where TNodeTypeResolver : INodeTypeResolver
		{
			return WithoutNodeTypeResolver(typeof(TNodeTypeResolver));
		}

		public DeserializerBuilder WithoutNodeTypeResolver(Type nodeTypeResolverType)
		{
			if (nodeTypeResolverType == null)
			{
				throw new ArgumentNullException("nodeTypeResolverType");
			}
			nodeTypeResolverFactories.Remove(nodeTypeResolverType);
			return this;
		}

		public override DeserializerBuilder WithTagMapping(TagName tag, Type type)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (tagMappings.TryGetValue(tag, out Type value))
			{
				throw new ArgumentException($"Type already has a registered type '{value.FullName}' for tag '{tag}'", "tag");
			}
			tagMappings.Add(tag, type);
			return this;
		}

		public DeserializerBuilder WithTypeMapping<TInterface, TConcrete>() where TConcrete : TInterface
		{
			Type typeFromHandle = typeof(TInterface);
			Type typeFromHandle2 = typeof(TConcrete);
			if (!typeFromHandle.IsAssignableFrom(typeFromHandle2))
			{
				throw new InvalidOperationException("The type '" + typeFromHandle2.Name + "' does not implement interface '" + typeFromHandle.Name + "'.");
			}
			if (typeMappings.ContainsKey(typeFromHandle))
			{
				typeMappings[typeFromHandle] = typeFromHandle2;
			}
			else
			{
				typeMappings.Add(typeFromHandle, typeFromHandle2);
			}
			return this;
		}

		public DeserializerBuilder WithoutTagMapping(TagName tag)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (!tagMappings.Remove(tag))
			{
				throw new KeyNotFoundException($"Tag '{tag}' is not registered");
			}
			return this;
		}

		public DeserializerBuilder IgnoreUnmatchedProperties()
		{
			ignoreUnmatched = true;
			return this;
		}

		public DeserializerBuilder WithDuplicateKeyChecking()
		{
			duplicateKeyChecking = true;
			return this;
		}

		public IDeserializer Build()
		{
			return Deserializer.FromValueDeserializer(BuildValueDeserializer());
		}

		public IValueDeserializer BuildValueDeserializer()
		{
			return new AliasValueDeserializer(new NodeValueDeserializer(nodeDeserializerFactories.BuildComponentList(), nodeTypeResolverFactories.BuildComponentList(), typeConverter));
		}
	}
	public sealed class EmissionPhaseObjectGraphVisitorArgs
	{
		private readonly IEnumerable<IObjectGraphVisitor<Nothing>> preProcessingPhaseVisitors;

		public IObjectGraphVisitor<IEmitter> InnerVisitor { get; private set; }

		public IEventEmitter EventEmitter { get; private set; }

		public ObjectSerializer NestedObjectSerializer { get; private set; }

		public IEnumerable<IYamlTypeConverter> TypeConverters { get; private set; }

		public EmissionPhaseObjectGraphVisitorArgs(IObjectGraphVisitor<IEmitter> innerVisitor, IEventEmitter eventEmitter, IEnumerable<IObjectGraphVisitor<Nothing>> preProcessingPhaseVisitors, IEnumerable<IYamlTypeConverter> typeConverters, ObjectSerializer nestedObjectSerializer)
		{
			InnerVisitor = innerVisitor ?? throw new ArgumentNullException("innerVisitor");
			EventEmitter = eventEmitter ?? throw new ArgumentNullException("eventEmitter");
			this.preProcessingPhaseVisitors = preProcessingPhaseVisitors ?? throw new ArgumentNullException("preProcessingPhaseVisitors");
			TypeConverters = typeConverters ?? throw new ArgumentNullException("typeConverters");
			NestedObjectSerializer = nestedObjectSerializer ?? throw new ArgumentNullException("nestedObjectSerializer");
		}

		public T GetPreProcessingPhaseObjectGraphVisitor<T>() where T : IObjectGraphVisitor<Nothing>
		{
			return preProcessingPhaseVisitors.OfType<T>().Single();
		}
	}
	public abstract class EventInfo
	{
		public IObjectDescriptor Source { get; }

		protected EventInfo(IObjectDescriptor source)
		{
			Source = source ?? throw new ArgumentNullException("source");
		}
	}
	public class AliasEventInfo : EventInfo
	{
		public AnchorName Alias { get; }

		public bool NeedsExpansion { get; set; }

		public AliasEventInfo(IObjectDescriptor source, AnchorName alias)
			: base(source)
		{
			if (alias.IsEmpty)
			{
				throw new ArgumentNullException("alias");
			}
			Alias = alias;
		}
	}
	public class ObjectEventInfo : EventInfo
	{
		public AnchorName Anchor { get; set; }

		public TagName Tag { get; set; }

		protected ObjectEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	public sealed class ScalarEventInfo : ObjectEventInfo
	{
		public string RenderedValue { get; set; }

		public ScalarStyle Style { get; set; }

		public bool IsPlainImplicit { get; set; }

		public bool IsQuotedImplicit { get; set; }

		public ScalarEventInfo(IObjectDescriptor source)
			: base(source)
		{
			Style = source.ScalarStyle;
			RenderedValue = string.Empty;
		}
	}
	public sealed class MappingStartEventInfo : ObjectEventInfo
	{
		public bool IsImplicit { get; set; }

		public MappingStyle Style { get; set; }

		public MappingStartEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	public sealed class MappingEndEventInfo : EventInfo
	{
		public MappingEndEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	public sealed class SequenceStartEventInfo : ObjectEventInfo
	{
		public bool IsImplicit { get; set; }

		public SequenceStyle Style { get; set; }

		public SequenceStartEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	public sealed class SequenceEndEventInfo : EventInfo
	{
		public SequenceEndEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	public interface IAliasProvider
	{
		AnchorName GetAlias(object target);
	}
	public interface IDeserializer
	{
		T Deserialize<T>(string input);

		T Deserialize<T>(TextReader input);

		T Deserialize<T>(IParser parser);

		object? Deserialize(string input);

		object? Deserialize(TextReader input);

		object? Deserialize(IParser parser);

		object? Deserialize(string input, Type type);

		object? Deserialize(TextReader input, Type type);

		object? Deserialize(IParser parser, Type type);
	}
	public interface IEventEmitter
	{
		void Emit(AliasEventInfo eventInfo, IEmitter emitter);

		void Emit(ScalarEventInfo eventInfo, IEmitter emitter);

		void Emit(MappingStartEventInfo eventInfo, IEmitter emitter);

		void Emit(MappingEndEventInfo eventInfo, IEmitter emitter);

		void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter);

		void Emit(SequenceEndEventInfo eventInfo, IEmitter emitter);
	}
	public interface INamingConvention
	{
		string Apply(string value);
	}
	public interface INodeDeserializer
	{
		bool Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value);
	}
	public interface INodeTypeResolver
	{
		bool Resolve(NodeEvent? nodeEvent, ref Type currentType);
	}
	public interface IObjectAccessor
	{
		void Set(string name, object target, object value);

		object? Read(string name, object target);
	}
	public interface IObjectDescriptor
	{
		object? Value { get; }

		Type Type { get; }

		Type StaticType { get; }

		ScalarStyle ScalarStyle { get; }
	}
	public static class ObjectDescriptorExtensions
	{
		public static object NonNullValue(this IObjectDescriptor objectDescriptor)
		{
			return objectDescriptor.Value ?? throw new InvalidOperationException("Attempted to use a IObjectDescriptor of type '" + objectDescriptor.Type.FullName + "' whose Value is null at a point whete it is invalid to do so. This may indicate a bug in YamlDotNet.");
		}
	}
	public interface IObjectFactory
	{
		object Create(Type type);

		object? CreatePrimitive(Type type);

		bool GetDictionary(IObjectDescriptor descriptor, out IDictionary? dictionary, out Type[]? genericArguments);

		Type GetValueType(Type type);

		void ExecuteOnDeserializing(object value);

		void ExecuteOnDeserialized(object value);

		void ExecuteOnSerializing(object value);

		void ExecuteOnSerialized(object value);
	}
	public interface IObjectGraphTraversalStrategy
	{
		void Traverse<TContext>(IObjectDescriptor graph, IObjectGraphVisitor<TContext> visitor, TContext context);
	}
	public interface IObjectGraphVisitor<TContext>
	{
		bool Enter(IObjectDescriptor value, TContext context);

		bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, TContext context);

		bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, TContext context);

		void VisitScalar(IObjectDescriptor scalar, TContext context);

		void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, TContext context);

		void VisitMappingEnd(IObjectDescriptor mapping, TContext context);

		void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, TContext context);

		void VisitSequenceEnd(IObjectDescriptor sequence, TContext context);
	}
	public interface IPropertyDescriptor
	{
		string Name { get; }

		bool CanWrite { get; }

		Type Type { get; }

		Type? TypeOverride { get; set; }

		int Order { get; set; }

		ScalarStyle ScalarStyle { get; set; }

		T? GetCustomAttribute<T>() where T : Attribute;

		IObjectDescriptor Read(object target);

		void Write(object target, object? value);
	}
	public interface IRegistrationLocationSelectionSyntax<TBaseRegistrationType>
	{
		void InsteadOf<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;

		void Before<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;

		void After<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;

		void OnTop();

		void OnBottom();
	}
	public interface ITrackingRegistrationLocationSelectionSyntax<TBaseRegistrationType>
	{
		void InsteadOf<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;
	}
	public interface ISerializer
	{
		string Serialize(object? graph);

		string Serialize(object? graph, Type type);

		void Serialize(TextWriter writer, object? graph);

		void Serialize(TextWriter writer, object? graph, Type type);

		void Serialize(IEmitter emitter, object? graph);

		void Serialize(IEmitter emitter, object? graph, Type type);
	}
	public interface ITypeInspector
	{
		IEnumerable<IPropertyDescriptor> GetProperties(Type type, object? container);

		IPropertyDescriptor GetProperty(Type type, object? container, string name, [MaybeNullWhen(true)] bool ignoreUnmatched);
	}
	public interface ITypeResolver
	{
		Type Resolve(Type staticType, object? actualValue);
	}
	public interface IValueDeserializer
	{
		object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer);
	}
	public interface IValuePromise
	{
		event Action<object?> ValueAvailable;
	}
	public interface IValueSerializer
	{
		void SerializeValue(IEmitter emitter, object? value, Type? type);
	}
	public interface IYamlConvertible
	{
		void Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer);

		void Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer);
	}
	public delegate object? ObjectDeserializer(Type type);
	public delegate void ObjectSerializer(object? value, Type? type = null);
	[Obsolete("Please use IYamlConvertible instead")]
	public interface IYamlSerializable
	{
		void ReadYaml(IParser parser);

		void WriteYaml(IEmitter emitter);
	}
	public interface IYamlTypeConverter
	{
		bool Accepts(Type type);

		object? ReadYaml(IParser parser, Type type);

		void WriteYaml(IEmitter emitter, object? value, Type type);
	}
	internal sealed class LazyComponentRegistrationList<TArgument, TComponent> : IEnumerable<Func<TArgument, TComponent>>, IEnumerable
	{
		public sealed class LazyComponentRegistration
		{
			public readonly Type ComponentType;

			public readonly Func<TArgument, TComponent> Factory;

			public LazyComponentRegistration(Type componentType, Func<TArgument, TComponent> factory)
			{
				ComponentType = componentType;
				Factory = factory;
			}
		}

		public sealed class TrackingLazyComponentRegistration
		{
			public readonly Type ComponentType;

			public readonly Func<TComponent, TArgument, TComponent> Factory;

			public TrackingLazyComponentRegistration(Type componentType, Func<TComponent, TArgument, TComponent> factory)
			{
				ComponentType = componentType;
				Factory = factory;
			}
		}

		private class RegistrationLocationSelector : IRegistrationLocationSelectionSyntax<TComponent>
		{
			private readonly LazyComponentRegistrationList<TArgument, TComponent> registrations;

			private readonly LazyComponentRegistration newRegistration;

			public RegistrationLocationSelector(LazyComponentRegistrationList<TArgument, TComponent> registrations, LazyComponentRegistration newRegistration)
			{
				this.registrations = registrations;
				this.newRegistration = newRegistration;
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.InsteadOf<TRegistrationType>()
			{
				if (newRegistration.ComponentType != typeof(TRegistrationType))
				{
					registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				}
				int index = registrations.EnsureRegistrationExists<TRegistrationType>();
				registrations.entries[index] = newRegistration;
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.After<TRegistrationType>()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				int num = registrations.EnsureRegistrationExists<TRegistrationType>();
				registrations.entries.Insert(num + 1, newRegistration);
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.Before<TRegistrationType>()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				int index = registrations.EnsureRegistrationExists<TRegistrationType>();
				registrations.entries.Insert(index, newRegistration);
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.OnBottom()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				registrations.entries.Add(newRegistration);
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.OnTop()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				registrations.entries.Insert(0, newRegistration);
			}
		}

		private class TrackingRegistrationLocationSelector : ITrackingRegistrationLocationSelectionSyntax<TComponent>
		{
			private readonly LazyComponentRegistrationList<TArgument, TComponent> registrations;

			private readonly TrackingLazyComponentRegistration newRegistration;

			public TrackingRegistrationLocationSelector(LazyComponentRegistrationList<TArgument, TComponent> registrations, TrackingLazyComponentRegistration newRegistration)
			{
				this.registrations = registrations;
				this.newRegistration = newRegistration;
			}

			void ITrackingRegistrationLocationSelectionSyntax<TComponent>.InsteadOf<TRegistrationType>()
			{
				if (newRegistration.ComponentType != typeof(TRegistrationType))
				{
					registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				}
				int index = registrations.EnsureRegistrationExists<TRegistrationType>();
				Func<TArgument, TComponent> innerComponentFactory = registrations.entries[index].Factory;
				registrations.entries[index] = new LazyComponentRegistration(newRegistration.ComponentType, (TArgument arg) => newRegistration.Factory(innerComponentFactory(arg), arg));
			}
		}

		private readonly List<LazyComponentRegistration> entries = new List<LazyComponentRegistration>();

		public int Count => entries.Count;

		public IEnumerable<Func<TArgument, TComponent>> InReverseOrder
		{
			get
			{
				int i = entries.Count - 1;
				while (i >= 0)
				{
					yield return entries[i].Factory;
					int num = i - 1;
					i = num;
				}
			}
		}

		public LazyComponentRegistrationList<TArgument, TComponent> Clone()
		{
			LazyComponentRegistrationList<TArgument, TComponent> lazyComponentRegistrationList = new LazyComponentRegistrationList<TArgument, TComponent>();
			foreach (LazyComponentRegistration entry in entries)
			{
				lazyComponentRegistrationList.entries.Add(entry);
			}
			return lazyComponentRegistrationList;
		}

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

		public void Add(Type componentType, Func<TArgument, TComponent> factory)
		{
			entries.Add(new LazyComponentRegistration(componentType, factory));
		}

		public void Remove(Type componentType)
		{
			for (int i = 0; i < entries.Count; i++)
			{
				if (entries[i].ComponentType == componentType)
				{
					entries.RemoveAt(i);
					return;
				}
			}
			throw new KeyNotFoundException("A component registration of type '" + componentType.FullName + "' was not found.");
		}

		public IRegistrationLocationSelectionSyntax<TComponent> CreateRegistrationLocationSelector(Type componentType, Func<TArgument, TComponent> factory)
		{
			return new RegistrationLocationSelector(this, new LazyComponentRegistration(componentType, factory));
		}

		public ITrackingRegistrationLocationSelectionSyntax<TComponent> CreateTrackingRegistrationLocationSelector(Type componentType, Func<TComponent, TArgument, TComponent> factory)
		{
			return new TrackingRegistrationLocationSelector(this, new TrackingLazyComponentRegistration(componentType, factory));
		}

		public IEnumerator<Func<TArgument, TComponent>> GetEnumerator()
		{
			return entries.Select((LazyComponentRegistration e) => e.Factory).GetEnumerator();
		}

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

		private int IndexOfRegistration(Type registrationType)
		{
			for (int i = 0; i < entries.Count; i++)
			{
				if (registrationType == entries[i].ComponentType)
				{
					return i;
				}
			}
			return -1;
		}

		private void EnsureNoDuplicateRegistrationType(Type componentType)
		{
			if (IndexOfRegistration(componentType) != -1)
			{
				throw new InvalidOperationException("A component of type '" + componentType.FullName + "' has already been registered.");
			}
		}

		private int EnsureRegistrationExists<TRegistrationType>()
		{
			int num = IndexOfRegistration(typeof(TRegistrationType));
			if (num == -1)
			{
				throw new InvalidOperationException("A component of type '" + typeof(TRegistrationType).FullName + "' has not been registered.");
			}
			return num;
		}
	}
	internal static class LazyComponentRegistrationListExtensions
	{
		public static TComponent BuildComponentChain<TComponent>(this LazyComponentRegistrationList<TComponent, TComponent> registrations, TComponent innerComponent)
		{
			return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func<TComponent, TComponent> factory) => factory(inner));
		}

		public static TComponent BuildComponentChain<TArgument, TComponent>(this LazyComponentRegistrationList<TArgument, TComponent> registrations, TComponent innerComponent, Func<TComponent, TArgument> argumentBuilder)
		{
			return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func<TArgument, TComponent> factory) => factory(argumentBuilder(inner)));
		}

		public static List<TComponent> BuildComponentList<TComponent>(this LazyComponentRegistrationList<Nothing, TComponent> registrations)
		{
			return registrations.Select((Func<Nothing, TComponent> factory) => factory(default(Nothing))).ToList();
		}

		public static List<TComponent> BuildComponentList<TArgument, TComponent>(this LazyComponentRegistrationList<TArgument, TComponent> registrations, TArgument argument)
		{
			return registrations.Select((Func<TArgument, TComponent> factory) => factory(argument)).ToList();
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct Nothing
	{
	}
	public sealed class ObjectDescriptor : IObjectDescriptor
	{
		public object? Value { get; private set; }

		public Type Type { get; private set; }

		public Type StaticType { get; private set; }

		public ScalarStyle ScalarStyle { get; private set; }

		public ObjectDescriptor(object? value, Type type, Type staticType)
			: this(value, type, staticType, ScalarStyle.Any)
		{
		}

		public ObjectDescriptor(object? value, Type type, Type staticType, ScalarStyle scalarStyle)
		{
			Value = value;
			Type = type ?? throw new ArgumentNullException("type");
			StaticType = staticType ?? throw new ArgumentNullException("staticType");
			ScalarStyle = scalarStyle;
		}
	}
	public delegate IObjectGraphTraversalStrategy ObjectGraphTraversalStrategyFactory(ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable<IYamlTypeConverter> typeConverters, int maximumRecursion);
	public sealed class PropertyDescriptor : IPropertyDescriptor
	{
		private readonly IPropertyDescriptor baseDescriptor;

		public string Name { get; set; }

		public Type Type => baseDescriptor.Type;

		public Type? TypeOverride
		{
			get
			{
				return baseDescriptor.TypeOverride;
			}
			set
			{
				baseDescriptor.TypeOverride = value;
			}
		}

		public int Order { get; set; }

		public ScalarStyle ScalarStyle
		{
			get
			{
				return baseDescriptor.ScalarStyle;
			}
			set
			{
				baseDescriptor.ScalarStyle = value;
			}
		}

		public bool CanWrite => baseDescriptor.CanWrite;

		public PropertyDescriptor(IPropertyDescriptor baseDescriptor)
		{
			this.baseDescriptor = baseDescriptor;
			Name = baseDescriptor.Name;
		}

		public void Write(object target, object? value)
		{
			baseDescriptor.Write(target, value);
		}

		public T? GetCustomAttribute<T>() where T : Attribute
		{
			return baseDescriptor.GetCustomAttribute<T>();
		}

		public IObjectDescriptor Read(object target)
		{
			return baseDescriptor.Read(target);
		}
	}
	public sealed class Serializer : ISerializer
	{
		private readonly IValueSerializer valueSerializer;

		private readonly EmitterSettings emitterSettings;

		public Serializer()
			: this(new SerializerBuilder().BuildValueSerializer(), EmitterSettings.Default)
		{
		}

		private Serializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings)
		{
			this.valueSerializer = valueSerializer ?? throw new ArgumentNullException("valueSerializer");
			this.emitterSettings = emitterSettings ?? throw new ArgumentNullException("emitterSettings");
		}

		public static Serializer FromValueSerializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings)
		{
			return new Serializer(valueSerializer, emitterSettings);
		}

		public string Serialize(object? graph)
		{
			using StringWriter stringWriter = new StringWriter();
			Serialize(stringWriter, graph);
			return stringWriter.ToString();
		}

		public string Serialize(object? graph, Type type)
		{
			using StringWriter stringWriter = new StringWriter();
			Serialize(stringWriter, graph, type);
			return stringWriter.ToString();
		}

		public void Serialize(TextWriter writer, object? graph)
		{
			Serialize(new Emitter(writer, emitterSettings), graph);
		}

		public void Serialize(TextWriter writer, object? graph, Type type)
		{
			Serialize(new Emitter(writer, emitterSettings), graph, type);
		}

		public void Serialize(IEmitter emitter, object? graph)
		{
			if (emitter == null)
			{
				throw new ArgumentNullException("emitter");
			}
			EmitDocument(emitter, graph, null);
		}

		public void Serialize(IEmitter emitter, object? graph, Type type)
		{
			if (emitter == null)
			{
				throw new ArgumentNullException("emitter");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			EmitDocument(emitter, graph, type);
		}

		private void EmitDocument(IEmitter emitter, object? graph, Type? type)
		{
			emitter.Emit(new YamlDotNet.Core.Events.StreamStart());
			emitter.Emit(new YamlDotNet.Core.Events.DocumentStart());
			valueSerializer.SerializeValue(emitter, graph, type);
			emitter.Emit(new YamlDotNet.Core.Events.DocumentEnd(isImplicit: true));
			emitter.Emit(new YamlDotNet.Core.Events.StreamEnd());
		}
	}
	public sealed class SerializerBuilder : BuilderSkeleton<SerializerBuilder>
	{
		private class ValueSerializer : IValueSerializer
		{
			private readonly IObjectGraphTraversalStrategy traversalStrategy;

			private readonly IEventEmitter eventEmitter;

			private readonly IEnumerable<IYamlTypeConverter> typeConverters;

			private readonly LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories;

			private readonly LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories;

			public ValueSerializer(IObjectGraphTraversalStrategy traversalStrategy, IEventEmitter eventEmitter, IEnumerable<IYamlTypeConverter> typeConverters, LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories, LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories)
			{
				this.traversalStrategy = traversalStrategy;
				this.eventEmitter = eventEmitter;
				this.typeConverters = typeConverters;
				this.preProcessingPhaseObjectGraphVisitorFactories = preProcessingPhaseObjectGraphVisitorFactories;
				this.emissionPhaseObjectGraphVisitorFactories = emissionPhaseObjectGraphVisitorFactories;
			}

			public void SerializeValue(IEmitter emitter, object? value, Type? type)
			{
				Type type2 = type ?? ((value != null) ? value.GetType() : typeof(object));
				Type staticType = type ?? typeof(object);
				ObjectDescriptor graph = new ObjectDescriptor(value, type2, staticType);
				List<IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters);
				foreach (IObjectGraphVisitor<Nothing> item in preProcessingPhaseObjectGraphVisitors)
				{
					traversalStrategy.Traverse(graph, item, default(Nothing));
				}
				IObjectGraphVisitor<IEmitter> visitor = emissionPhaseObjectGraphVisitorFactories.BuildComponentChain<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>>(new EmittingObjectGraphVisitor(eventEmitter), (IObjectGraphVisitor<IEmitter> inner) => new EmissionPhaseObjectGraphVisitorArgs(inner, eventEmitter, preProcessingPhaseObjectGraphVisitors, typeConverters, NestedObjectSerializer));
				traversalStrategy.Traverse(graph, visitor, emitter);
				void NestedObjectSerializer(object? v, Type? t)
				{
					SerializeValue(emitter, v, t);
				}
			}
		}

		private ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory;

		private readonly LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories;

		private readonly LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories;

		private readonly LazyComponentRegistrationList<IEventEmitter, IEventEmitter> eventEmitterFactories;

		private readonly IDictionary<Type, TagName> tagMappings = new Dictionary<Type, TagName>();

		private readonly IObjectFactory objectFactory;

		private int maximumRecursion = 50;

		private EmitterSettings emitterSettings = EmitterSettings.Default;

		private DefaultValuesHandling defaultValuesHandlingConfiguration;

		private ScalarStyle defaultScalarStyle;

		private bool quoteNecessaryStrings;

		private bool quoteYaml1_1Strings;

		protected override SerializerBuilder Self => this;

		public SerializerBuilder()
			: base((ITypeResolver)new DynamicTypeResolver())
		{
			typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner));
			typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner);
			typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner));
			typeInspectorFactories.Add(typeof(YamlAttributeOverridesInspector), (ITypeInspector inner) => (overrides == null) ? inner : new YamlAttributeOverridesInspector(inner, overrides.Clone()));
			preProcessingPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> { 
			{
				typeof(AnchorAssigner),
				(IEnumerable<IYamlTypeConverter> typeConverters) => new AnchorAssigner(typeConverters)
			} };
			emissionPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>>
			{
				{
					typeof(CustomSerializationObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new CustomSerializationObjectGraphVisitor(args.InnerVisitor, args.TypeConverters, args.NestedObjectSerializer)
				},
				{
					typeof(AnchorAssigningObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new AnchorAssigningObjectGraphVisitor(args.InnerVisitor, args.EventEmitter, args.GetPreProcessingPhaseObjectGraphVisitor<AnchorAssigner>())
				},
				{
					typeof(DefaultValuesObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new DefaultValuesObjectGraphVisitor(defaultValuesHandlingConfiguration, args.InnerVisitor, new DefaultObjectFactory())
				},
				{
					typeof(CommentsObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new CommentsObjectGraphVisitor(args.InnerVisitor)
				}
			};
			eventEmitterFactories = new LazyComponentRegistrationList<IEventEmitter, IEventEmitter> { 
			{
				typeof(TypeAssigningEventEmitter),
				(IEventEmitter inner) => new TypeAssigningEventEmitter(inner, requireTagWhenStaticAndActualTypesAreDifferent: false, tagMappings, quoteNecessaryStrings, quoteYaml1_1Strings, defaultScalarStyle, yamlFormatter)
			} };
			objectFactory = new DefaultObjectFactory();
			objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable<IYamlTypeConverter> typeConverters, int maximumRecursion) => new FullObjectGraphTraversalStrategy(typeInspector, typeResolver, maximumRecursion, namingConvention, objectFactory);
		}

		public SerializerBuilder WithQuotingNecessaryStrings(bool quoteYaml1_1Strings = false)
		{
			quoteNecessaryStrings = true;
			this.quoteYaml1_1Strings = quoteYaml1_1Strings;
			return this;
		}

		public SerializerBuilder WithDefaultScalarStyle(ScalarStyle style)
		{
			defaultScalarStyle = style;
			return this;
		}

		public SerializerBuilder WithMaximumRecursion(int maximumRecursion)
		{
			if (maximumRecursion <= 0)
			{
				throw new ArgumentOutOfRangeException("maximumRecursion", $"The maximum recursion specified ({maximumRecursion}) is invalid. It should be a positive integer.");
			}
			this.maximumRecursion = maximumRecursion;
			return this;
		}

		public SerializerBuilder WithEventEmitter<TEventEmitter>(Func<IEventEmitter, TEventEmitter> eventEmitterFactory) where TEventEmitter : IEventEmitter
		{
			return WithEventEmitter(eventEmitterFactory, delegate(IRegistrationLocationSelectionSyntax<IEventEmitter> w)
			{
				w.OnTop();
			});
		}

		public SerializerBuilder WithEventEmitter<TEventEmitter>(Func<IEventEmitter, TEventEmitter> eventEmitterFactory, Action<IRegistrationLocationSelectionSyntax<IEventEmitter>> where) where TEventEmitter : IEventEmitter
		{
			if (eventEmitterFactory == null)
			{
				throw new ArgumentNullException("eventEmitterFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(eventEmitterFactories.CreateRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter inner) => eventEmitterFactory(inner)));
			return Self;
		}

		public SerializerBuilder WithEventEmitter<TEventEmitter>(WrapperFactory<IEventEmitter, IEventEmitter, TEventEmitter> eventEmitterFactory, Action<ITrackingRegistrationLocationSelectionSyntax<IEventEmitter>> where) where TEventEmitter : IEventEmitter
		{
			if (eventEmitterFactory == null)
			{
				throw new ArgumentNullException("eventEmitterFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(eventEmitterFactories.CreateTrackingRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter wrapped, IEventEmitter inner) => eventEmitterFactory(wrapped, inner)));
			return Self;
		}

		public SerializerBuilder WithoutEventEmitter<TEventEmitter>() where TEventEmitter : IEventEmitter
		{
			return WithoutEventEmitter(typeof(TEventEmitter));
		}

		public SerializerBuilder WithoutEventEmitter(Type eventEmitterType)
		{
			if (eventEmitterType == null)
			{
				throw new ArgumentNullException("eventEmitterType");
			}
			eventEmitterFactories.Remove(eventEmitterType);
			return this;
		}

		public override SerializerBuilder WithTagMapping(TagName tag, Type type)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (tagMappings.TryGetValue(type, out var value))
			{
				throw new ArgumentException($"Type already has a registered tag '{value}' for type '{type.FullName}'", "type");
			}
			tagMappings.Add(type, tag);
			return this;
		}

		public SerializerBuilder WithoutTagMapping(Type type)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (!tagMappings.Remove(type))
			{
				throw new KeyNotFoundException("Tag for type '" + type.FullName + "' is not registered");
			}
			return this;
		}

		public SerializerBuilder EnsureRoundtrip()
		{
			objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable<IYamlTypeConverter> typeConverters, int maximumRecursion) => new RoundtripObjectGraphTraversalStrategy(typeConverters, typeInspector, typeResolver, maximumRecursion, namingConvention, settings, objectFactory);
			WithEventEmitter((IEventEmitter inner) => new TypeAssigningEventEmitter(inner, requireTagWhenStaticAndActualTypesAreDifferent: true, tagMappings, quoteNecessaryStrings, quoteYaml1_1Strings, defaultScalarStyle, yamlFormatter), delegate(IRegistrationLocationSelectionSyntax<IEventEmitter> loc)
			{
				loc.InsteadOf<TypeAssigningEventEmitter>();
			});
			return WithTypeInspector((ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner), delegate(IRegistrationLocationSelectionSyntax<ITypeInspector> loc)
			{
				loc.OnBottom();
			});
		}

		public SerializerBuilder DisableAliases()
		{
			preProcessingPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigner));
			emissionPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigningObjectGraphVisitor));
			return this;
		}

		[Obsolete("The default behavior is now to always emit default values, thefore calling this method has no effect. This behavior is now controlled by ConfigureDefaultValuesHandling.", true)]
		public SerializerBuilder EmitDefaults()
		{
			return ConfigureDefaultValuesHandling(DefaultValuesHandling.Preserve);
		}

		public SerializerBuilder ConfigureDefaultValuesHandling(DefaultValuesHandling configuration)
		{
			defaultValuesHandlingConfiguration = configuration;
			return this;
		}

		public SerializerBuilder JsonCompatible()
		{
			emitterSettings = emitterSettings.WithMaxSimpleKeyLength(int.MaxValue).WithoutAnchorName();
			return WithTypeConverter(new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: true), delegate(IRegistrationLocationSelectionSyntax<IYamlTypeConverter> w)
			{
				w.InsteadOf<YamlDotNet.Serialization.Converters.GuidConverter>();
			}).WithTypeConverter(new YamlDotNet.Serialization.Converters.DateTimeConverter(DateTimeKind.Utc, null, true)).WithEventEmitter((IEventEmitter inner) => new JsonEventEmitter(inner, yamlFormatter), delegate(IRegistrationLocationSelectionSyntax<IEventEmitter> loc)
			{
				loc.InsteadOf<TypeAssigningEventEmitter>();
			});
		}

		public SerializerBuilder WithNewLine(string newLine)
		{
			emitterSettings = emitterSettings.WithNewLine(newLine);
			return this;
		}

		public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor<TObjectGraphVisitor>(TObjectGraphVisitor objectGraphVisitor) where TObjectGraphVisitor : IObjectGraphVisitor<Nothing>
		{
			return WithPreProcessingPhaseObjectGraphVisitor(objectGraphVisitor, delegate(IRegistrationLocationSelectionSyntax<IObjectGraphVisitor<Nothing>> w)
			{
				w.OnTop();
			});
		}

		public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor<TObjectGraphVisitor>(TObjectGraphVisitor objectGraphVisitor, Action<IRegistrationLocationSelectionSyntax<IObjectGraphVisitor<Nothing>>> where) where TObjectGraphVisitor : IObjectGraphVisitor<Nothing>
		{
			if (objectGraphVisitor == null)
			{
				throw new ArgumentNullException("objectGraphVisitor");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(preProcessingPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IEnumerable<IYamlTypeConverter> _) => objectGraphVisitor));
			return this;
		}

		public SerializerBuilder WithPreProcessingPhaseObjectGraphVisitor<TObjectGraphVisitor>(WrapperFactory<IObjectGraphVisitor<Nothing>, TObjectGraphVisitor> objectGraphVisitorFactory, Action<ITrackingRegistrationLocationSelectionSyntax<IObjectGraphVisitor<Nothing>>> where) where TObjectGraphVisitor : IObjectGraphVisitor<Nothing>
		{
			if (objectGraphVisitorFactory == null)
			{
				throw new ArgumentNullException("objectGraphVisitorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(preProcessingPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor<Nothing> wrapped, IEnumerable<IYamlTypeConverter> _) => objectGraphVisitorFactory(wrapped)));
			return this;
		}

		public SerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor<TObjectGraphVisitor>() where TObjectGraphVisitor : IObjectGraphVisitor<Nothing>
		{
			return WithoutPreProcessingPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor));
		}

		public SerializerBuilder WithoutPreProcessingPhaseObjectGraphVisitor(Type objectGraphVisitorType)
		{
			if (objectGraphVisitorType == null)
			{
				throw new ArgumentNullException("objectGraphVisitorType");
			}
			preProcessingPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType);
			return this;
		}

		public SerializerBuilder WithObjectGraphTraversalStrategyFactory(ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory)
		{
			this.objectGraphTraversalStrategyFactory = objectGraphTraversalStrategyFactory;
			return this;
		}

		public SerializerBuilder WithEmissionPhaseObjectGraphVisitor<TObjectGraphVisitor>(Func<EmissionPhaseObjectGraphVisitorArgs, TObjectGraphVisitor> objectGraphVisitorFactory) where TObjectGraphVisitor : IObjectGraphVisitor<IEmitter>
		{
			return WithEmissionPhaseObjectGraphVisitor(objectGraphVisitorFactory, delegate(IRegistrationLocationSelectionSyntax<IObjectGraphVisitor<IEmitter>> w)
			{
				w.OnTop();
			});
		}

		public SerializerBuilder WithEmissionPhaseObjectGraphVisitor<TObjectGraphVisitor>(Func<EmissionPhaseObjectGraphVisitorArgs, TObjectGraphVisitor> objectGraphVisitorFactory, Action<IRegistrationLocationSelectionSyntax<IObjectGraphVisitor<IEmitter>>> where) where TObjectGraphVisitor : IObjectGraphVisitor<IEmitter>
		{
			if (objectGraphVisitorFactory == null)
			{
				throw new ArgumentNullException("objectGraphVisitorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(emissionPhaseObjectGraphVisitorFactories.CreateRegistrationLocationSelector(typeof(TObjectGraphVisitor), (EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory(args)));
			return this;
		}

		public SerializerBuilder WithEmissionPhaseObjectGraphVisitor<TObjectGraphVisitor>(WrapperFactory<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>, TObjectGraphVisitor> objectGraphVisitorFactory, Action<ITrackingRegistrationLocationSelectionSyntax<IObjectGraphVisitor<IEmitter>>> where) where TObjectGraphVisitor : IObjectGraphVisitor<IEmitter>
		{
			if (objectGraphVisitorFactory == null)
			{
				throw new ArgumentNullException("objectGraphVisitorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(emissionPhaseObjectGraphVisitorFactories.CreateTrackingRegistrationLocationSelector(typeof(TObjectGraphVisitor), (IObjectGraphVisitor<IEmitter> wrapped, EmissionPhaseObjectGraphVisitorArgs args) => objectGraphVisitorFactory(wrapped, args)));
			return this;
		}

		public SerializerBuilder WithoutEmissionPhaseObjectGraphVisitor<TObjectGraphVisitor>() where TObjectGraphVisitor : IObjectGraphVisitor<IEmitter>
		{
			return WithoutEmissionPhaseObjectGraphVisitor(typeof(TObjectGraphVisitor));
		}

		public SerializerBuilder WithoutEmissionPhaseObjectGraphVisitor(Type objectGraphVisitorType)
		{
			if (objectGraphVisitorType == null)
			{
				throw new ArgumentNullException("objectGraphVisitorType");
			}
			emissionPhaseObjectGraphVisitorFactories.Remove(objectGraphVisitorType);
			return this;
		}

		public SerializerBuilder WithIndentedSequences()
		{
			emitterSettings = emitterSettings.WithIndentedSequences();
			return this;
		}

		public ISerializer Build()
		{
			return Serializer.FromValueSerializer(BuildValueSerializer(), emitterSettings);
		}

		public IValueSerializer BuildValueSerializer()
		{
			IEnumerable<IYamlTypeConverter> typeConverters = BuildTypeConverters();
			ITypeInspector typeInspector = BuildTypeInspector();
			IObjectGraphTraversalStrategy traversalStrategy = objectGraphTraversalStrategyFactory(typeInspector, typeResolver, typeConverters, maximumRecursion);
			IEventEmitter eventEmitter = eventEmitterFactories.BuildComponentChain(new WriterEventEmitter());
			return new ValueSerializer(traversalStrategy, eventEmitter, typeConverters, preProcessingPhaseObjectGraphVisitorFactories.Clone(), emissionPhaseObjectGraphVisitorFactories.Clone());
		}

		internal ITypeInspector BuildTypeInspector()
		{
			ITypeInspector typeInspector = new ReadablePropertiesTypeInspector(typeResolver, includeNonPublicProperties);
			if (!ignoreFields)
			{
				typeInspector = new CompositeTypeInspector(new ReadableFieldsTypeInspector(typeResolver), typeInspector);
			}
			return typeInspectorFactories.BuildComponentChain(typeInspector);
		}
	}
	public class Settings
	{
		public bool AllowPrivateConstructors { get; set; }
	}
	public abstract class StaticBuilderSkeleton<TBuilder> where TBuilder : StaticBuilderSkeleton<TBuilder>
	{
		internal INamingConvention namingConvention = NullNamingConvention.Instance;

		internal ITypeResolver typeResolver;

		internal readonly LazyComponentRegistrationList<Nothing, IYamlTypeConverter> typeConverterFactories;

		internal readonly LazyComponentRegistrationList<ITypeInspector, ITypeInspector> typeInspectorFactories;

		internal bool includeNonPublicProperties;

		internal Settings settings;

		internal YamlFormatter yamlFormatter = YamlFormatter.Default;

		protected abstract TBuilder Self { get; }

		internal StaticBuilderSkeleton(ITypeResolver typeResolver)
		{
			typeConverterFactories = new LazyComponentRegistrationList<Nothing, IYamlTypeConverter> { 
			{
				typeof(YamlDotNet.Serialization.Converters.GuidConverter),
				(Nothing _) => new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: false)
			} };
			typeInspectorFactories = new LazyComponentRegistrationList<ITypeInspector, ITypeInspector>();
			this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver");
			settings = new Settings();
		}

		public TBuilder WithNamingConvention(INamingConvention namingConvention)
		{
			this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention");
			return Self;
		}

		public TBuilder WithTypeResolver(ITypeResolver typeResolver)
		{
			this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver");
			return Self;
		}

		public abstract TBuilder WithTagMapping(TagName tag, Type type);

		public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter)
		{
			return WithTypeConverter(typeConverter, delegate(IRegistrationLocationSelectionSyntax<IYamlTypeConverter> w)
			{
				w.OnTop();
			});
		}

		public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter, Action<IRegistrationLocationSelectionSyntax<IYamlTypeConverter>> where)
		{
			if (typeConverter == null)
			{
				throw new ArgumentNullException("typeConverter");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeConverterFactories.CreateRegistrationLocationSelector(typeConverter.GetType(), (Nothing _) => typeConverter));
			return Self;
		}

		public TBuilder WithTypeConverter<TYamlTypeConverter>(WrapperFactory<IYamlTypeConverter, IYamlTypeConverter> typeConverterFactory, Action<ITrackingRegistrationLocationSelectionSyntax<IYamlTypeConverter>> where) where TYamlTypeConverter : IYamlTypeConverter
		{
			if (typeConverterFactory == null)
			{
				throw new ArgumentNullException("typeConverterFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeConverterFactories.CreateTrackingRegistrationLocationSelector(typeof(TYamlTypeConverter), (IYamlTypeConverter wrapped, Nothing _) => typeConverterFactory(wrapped)));
			return Self;
		}

		public TBuilder WithoutTypeConverter<TYamlTypeConverter>() where TYamlTypeConverter : IYamlTypeConverter
		{
			return WithoutTypeConverter(typeof(TYamlTypeConverter));
		}

		public TBuilder WithoutTypeConverter(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			typeConverterFactories.Remove(converterType);
			return Self;
		}

		public TBuilder WithTypeInspector<TTypeInspector>(Func<ITypeInspector, TTypeInspector> typeInspectorFactory) where TTypeInspector : ITypeInspector
		{
			return WithTypeInspector(typeInspectorFactory, delegate(IRegistrationLocationSelectionSyntax<ITypeInspector> w)
			{
				w.OnTop();
			});
		}

		public TBuilder WithTypeInspector<TTypeInspector>(Func<ITypeInspector, TTypeInspector> typeInspectorFactory, Action<IRegistrationLocationSelectionSyntax<ITypeInspector>> where) where TTypeInspector : ITypeInspector
		{
			if (typeInspectorFactory == null)
			{
				throw new ArgumentNullException("typeInspectorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeInspectorFactories.CreateRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector inner) => typeInspectorFactory(inner)));
			return Self;
		}

		public TBuilder WithTypeInspector<TTypeInspector>(WrapperFactory<ITypeInspector, ITypeInspector, TTypeInspector> typeInspectorFactory, Action<ITrackingRegistrationLocationSelectionSyntax<ITypeInspector>> where) where TTypeInspector : ITypeInspector
		{
			if (typeInspectorFactory == null)
			{
				throw new ArgumentNullException("typeInspectorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeInspectorFactories.CreateTrackingRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector wrapped, ITypeInspector inner) => typeInspectorFactory(wrapped, inner)));
			return Self;
		}

		public TBuilder WithoutTypeInspector<TTypeInspector>() where TTypeInspector : ITypeInspector
		{
			return WithoutTypeInspector(typeof(TTypeInspector));
		}

		public TBuilder WithoutTypeInspector(Type inspectorType)
		{
			if (inspectorType == null)
			{
				throw new ArgumentNullException("inspectorType");
			}
			typeInspectorFactories.Remove(inspectorType);
			return Self;
		}

		public TBuilder WithYamlFormatter(YamlFormatter formatter)
		{
			yamlFormatter = formatter ?? throw new ArgumentNullException("formatter");
			return Self;
		}

		protected IEnumerable<IYamlTypeConverter> BuildTypeConverters()
		{
			return typeConverterFactories.BuildComponentList();
		}
	}
	public abstract class StaticContext
	{
		public virtual bool IsKnownType(Type type)
		{
			throw new NotImplementedException();
		}

		public virtual ITypeResolver GetTypeResolver()
		{
			throw new NotImplementedException();
		}

		public virtual StaticObjectFactory GetFactory()
		{
			throw new NotImplementedException();
		}

		public virtual ITypeInspector GetTypeInspector()
		{
			throw new NotImplementedException();
		}
	}
	public sealed class StaticDeserializerBuilder : StaticBuilderSkeleton<StaticDeserializerBuilder>
	{
		private readonly StaticContext context;

		private readonly StaticObjectFactory factory;

		private readonly LazyComponentRegistrationList<Nothing, INodeDeserializer> nodeDeserializerFactories;

		private readonly LazyComponentRegistrationList<Nothing, INodeTypeResolver> nodeTypeResolverFactories;

		private readonly Dictionary<TagName, Type> tagMappings;

		private readonly ITypeConverter typeConverter;

		private readonly Dictionary<Type, Type> typeMappings;

		private bool ignoreUnmatched;

		private bool duplicateKeyChecking;

		private bool attemptUnknownTypeDeserialization;

		protected override StaticDeserializerBuilder Self => this;

		public StaticDeserializerBuilder(StaticContext context)
			: base(context.GetTypeResolver())
		{
			this.context = context;
			factory = context.GetFactory();
			typeMappings = new Dictionary<Type, Type>();
			tagMappings = new Dictionary<TagName, Type>
			{
				{
					FailsafeSchema.Tags.Map,
					typeof(Dictionary<object, object>)
				},
				{
					FailsafeSchema.Tags.Str,
					typeof(string)
				},
				{
					JsonSchema.Tags.Bool,
					typeof(bool)
				},
				{
					JsonSchema.Tags.Float,
					typeof(double)
				},
				{
					JsonSchema.Tags.Int,
					typeof(int)
				},
				{
					DefaultSchema.Tags.Timestamp,
					typeof(DateTime)
				}
			};
			typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner));
			typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner);
			typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner));
			nodeDeserializerFactories = new LazyComponentRegistrationList<Nothing, INodeDeserializer>
			{
				{
					typeof(YamlConvertibleNodeDeserializer),
					(Nothing _) => new YamlConvertibleNodeDeserializer(factory)
				},
				{
					typeof(YamlSerializableNodeDeserializer),
					(Nothing _) => new YamlSerializableNodeDeserializer(factory)
				},
				{
					typeof(TypeConverterNodeDeserializer),
					(Nothing _) => new TypeConverterNodeDeserializer(BuildTypeConverters())
				},
				{
					typeof(NullNodeDeserializer),
					(Nothing _) => new NullNodeDeserializer()
				},
				{
					typeof(ScalarNodeDeserializer),
					(Nothing _) => new ScalarNodeDeserializer(attemptUnknownTypeDeserialization, typeConverter, yamlFormatter)
				},
				{
					typeof(StaticArrayNodeDeserializer),
					(Nothing _) => new StaticArrayNodeDeserializer(factory)
				},
				{
					typeof(StaticDictionaryNodeDeserializer),
					(Nothing _) => new StaticDictionaryNodeDeserializer(factory, duplicateKeyChecking)
				},
				{
					typeof(StaticCollectionNodeDeserializer),
					(Nothing _) => new StaticCollectionNodeDeserializer(factory)
				},
				{
					typeof(ObjectNodeDeserializer),
					(Nothing _) => new ObjectNodeDeserializer(factory, BuildTypeInspector(), ignoreUnmatched, duplicateKeyChecking, typeConverter)
				}
			};
			nodeTypeResolverFactories = new LazyComponentRegistrationList<Nothing, INodeTypeResolver>
			{
				{
					typeof(MappingNodeTypeResolver),
					(Nothing _) => new MappingNodeTypeResolver(typeMappings)
				},
				{
					typeof(YamlConvertibleTypeResolver),
					(Nothing _) => new YamlConvertibleTypeResolver()
				},
				{
					typeof(YamlSerializableTypeResolver),
					(Nothing _) => new YamlSerializableTypeResolver()
				},
				{
					typeof(TagNodeTypeResolver),
					(Nothing _) => new TagNodeTypeResolver(tagMappings)
				},
				{
					typeof(PreventUnknownTagsNodeTypeResolver),
					(Nothing _) => new PreventUnknownTagsNodeTypeResolver()
				},
				{
					typeof(DefaultContainersNodeTypeResolver),
					(Nothing _) => new DefaultContainersNodeTypeResolver()
				}
			};
			typeConverter = new NullTypeConverter();
		}

		internal ITypeInspector BuildTypeInspector()
		{
			ITypeInspector typeInspector = context.GetTypeInspector();
			return typeInspectorFactories.BuildComponentChain(typeInspector);
		}

		public StaticDeserializerBuilder WithAttemptingUnquotedStringTypeDeserialization()
		{
			attemptUnknownTypeDeserialization = true;
			return this;
		}

		public StaticDeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer)
		{
			return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax<INodeDeserializer> w)
			{
				w.OnTop();
			});
		}

		public StaticDeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer, Action<IRegistrationLocationSelectionSyntax<INodeDeserializer>> where)
		{
			if (nodeDeserializer == null)
			{
				throw new ArgumentNullException("nodeDeserializer");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeDeserializerFactories.CreateRegistrationLocationSelector(nodeDeserializer.GetType(), (Nothing _) => nodeDeserializer));
			return this;
		}

		public StaticDeserializerBuilder WithNodeDeserializer<TNodeDeserializer>(WrapperFactory<INodeDeserializer, TNodeDeserializer> nodeDeserializerFactory, Action<ITrackingRegistrationLocationSelectionSyntax<INodeDeserializer>> where) where TNodeDeserializer : INodeDeserializer
		{
			if (nodeDeserializerFactory == null)
			{
				throw new ArgumentNullException("nodeDeserializerFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeDeserializerFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeDeserializer), (INodeDeserializer wrapped, Nothing _) => nodeDeserializerFactory(wrapped)));
			return this;
		}

		public StaticDeserializerBuilder WithoutNodeDeserializer<TNodeDeserializer>() where TNodeDeserializer : INodeDeserializer
		{
			return WithoutNodeDeserializer(typeof(TNodeDeserializer));
		}

		public StaticDeserializerBuilder WithoutNodeDeserializer(Type nodeDeserializerType)
		{
			if (nodeDeserializerType == null)
			{
				throw new ArgumentNullException("nodeDeserializerType");
			}
			nodeDeserializerFactories.Remove(nodeDeserializerType);
			return this;
		}

		public StaticDeserializerBuilder WithTypeDiscriminatingNodeDeserializer(Action<ITypeDiscriminatingNodeDeserializerOptions> configureTypeDiscriminatingNodeDeserializerOptions, int maxDepth = -1, int maxLength = -1)
		{
			TypeDiscriminatingNodeDeserializerOptions typeDiscriminatingNodeDeserializerOptions = new TypeDiscriminatingNodeDeserializerOptions();
			configureTypeDiscriminatingNodeDeserializerOptions(typeDiscriminatingNodeDeserializerOptions);
			TypeDiscriminatingNodeDeserializer nodeDeserializer = new TypeDiscriminatingNodeDeserializer(nodeDeserializerFactories.BuildComponentList(), typeDiscriminatingNodeDeserializerOptions.discriminators, maxDepth, maxLength);
			return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax<INodeDeserializer> s)
			{
				s.Before<DictionaryNodeDeserializer>();
			});
		}

		public StaticDeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver)
		{
			return WithNodeTypeResolver(nodeTypeResolver, delegate(IRegistrationLocationSelectionSyntax<INodeTypeResolver> w)
			{
				w.OnTop();
			});
		}

		public StaticDeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver, Action<IRegistrationLocationSelectionSyntax<INodeTypeResolver>> where)
		{
			if (nodeTypeResolver == null)
			{
				throw new ArgumentNullException("nodeTypeResolver");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeTypeResolverFactories.CreateRegistrationLocationSelector(nodeTypeResolver.GetType(), (Nothing _) => nodeTypeResolver));
			return this;
		}

		public StaticDeserializerBuilder WithNodeTypeResolver<TNodeTypeResolver>(WrapperFactory<INodeTypeResolver, TNodeTypeResolver> nodeTypeResolverFactory, Action<ITrackingRegistrationLocationSelectionSyntax<INodeTypeResolver>> where) where TNodeTypeResolver : INodeTypeResolver
		{
			if (nodeTypeResolverFactory == null)
			{
				throw new ArgumentNullException("nodeTypeResolverFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeTypeResolverFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeTypeResolver), (INodeTypeResolver wrapped, Nothing _) => nodeTypeResolverFactory(wrapped)));
			return this;
		}

		public StaticDeserializerBuilder WithoutNodeTypeResolver<TNodeTypeResolver>() where TNodeTypeResolver : INodeTypeResolver
		{
			return WithoutNodeTypeResolver(typeof(TNodeTypeResolver));
		}

		public StaticDeserializerBuilder WithoutNodeTypeResolver(Type nodeTypeResolverType)
		{
			if (nodeTypeResolverType == null)
			{
				throw new ArgumentNullException("nodeTypeResolverType");
			}
			nodeTypeResolverFactories.Remove(nodeTypeResolverType);
			return this;
		}

		public override StaticDeserializerBuilder WithTagMapping(TagName tag, Type type)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (tagMappings.TryGetValue(tag, out Type value))
			{
				throw new ArgumentException($"Type already has a registered type '{value.FullName}' for tag '{tag}'", "tag");
			}
			tagMappings.Add(tag, type);
			return this;
		}

		public StaticDeserializerBuilder WithTypeMapping<TInterface, TConcrete>() where TConcrete : TInterface
		{
			Type typeFromHandle = typeof(TInterface);
			Type typeFromHandle2 = typeof(TConcrete);
			if (!typeFromHandle.IsAssignableFrom(typeFromHandle2))
			{
				throw new InvalidOperationException("The type '" + typeFromHandle2.Name + "' does not implement interface '" + typeFromHandle.Name + "'.");
			}
			if (typeMappings.ContainsKey(typeFromHandle))
			{
				typeMappings[typeFromHandle] = typeFromHandle2;
			}
			else
			{
				typeMappings.Add(typeFromHandle, typeFromHandle2);
			}
			return this;
		}

		public StaticDeserializerBuilder WithoutTagMapping(TagName tag)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (!tagMappings.Remove(tag))
			{
				throw new KeyNotFoundException($"Tag '{tag}' is not registered");
			}
			return this;
		}

		public StaticDeserializerBuilder IgnoreUnmatchedProperties()
		{
			ignoreUnmatched = true;
			return this;
		}

		public StaticDeserializerBuilder WithDuplicateKeyChecking()
		{
			duplicateKeyChecking = true;
			return this;
		}

		public IDeserializer Build()
		{
			return Deserializer.FromValueDeserializer(BuildValueDeserializer());
		}

		public IValueDeserializer BuildValueDeserializer()
		{
			return new AliasValueDeserializer(new NodeValueDeserializer(nodeDeserializerFactories.BuildComponentList(), nodeTypeResolverFactories.BuildComponentList(), typeConverter));
		}
	}
	public sealed class StaticSerializerBuilder : StaticBuilderSkeleton<StaticSerializerBuilder>
	{
		private class ValueSerializer : IValueSerializer
		{
			private readonly IObjectGraphTraversalStrategy traversalStrategy;

			private readonly IEventEmitter eventEmitter;

			private readonly IEnumerable<IYamlTypeConverter> typeConverters;

			private readonly LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories;

			private readonly LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories;

			public ValueSerializer(IObjectGraphTraversalStrategy traversalStrategy, IEventEmitter eventEmitter, IEnumerable<IYamlTypeConverter> typeConverters, LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories, LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories)
			{
				this.traversalStrategy = traversalStrategy;
				this.eventEmitter = eventEmitter;
				this.typeConverters = typeConverters;
				this.preProcessingPhaseObjectGraphVisitorFactories = preProcessingPhaseObjectGraphVisitorFactories;
				this.emissionPhaseObjectGraphVisitorFactories = emissionPhaseObjectGraphVisitorFactories;
			}

			public void SerializeValue(IEmitter emitter, object? value, Type? type)
			{
				Type type2 = type ?? ((value != null) ? value.GetType() : typeof(object));
				Type staticType = type ?? typeof(object);
				ObjectDescriptor graph = new ObjectDescriptor(value, type2, staticType);
				List<IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters);
				foreach (IObjectGraphVisitor<Nothing> item in preProcessingPhaseObjectGraphVisitors)
				{
					traversalStrategy.Traverse(graph, item, default(Nothing));
				}
				IObjectGraphVisitor<IEmitter> visitor = emissionPhaseObjectGraphVisitorFactories.BuildComponentChain<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>>(new EmittingObjectGraphVisitor(eventEmitter), (IObjectGraphVisitor<IEmitter> inner) => new EmissionPhaseObjectGraphVisitorArgs(inner, eventEmitter, preProcessingPhaseObjectGraphVisitors, typeConverters, NestedObjectSerializer));
				traversalStrategy.Traverse(graph, visitor, emitter);
				void NestedObjectSerializer(object? v, Type? t)
				{
					SerializeValue(emitter, v, t);
				}
			}
		}

		private readonly StaticContext context;

		private readonly StaticObjectFactory factory;

		private ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory;

		private readonly LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories;

		private readonly LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories;

		private readonly LazyComponentRegistrationList<IEventEmitter, IEventEmitter> eventEmitterFactories;

		private readonly IDictionary<Type, TagName> tagMappings = new Dictionary<Type, TagName>();

		private int maximumRecursion = 50;

		private EmitterSettings emitterSettings = EmitterSettings.Default;

		private DefaultValuesHandling defaultValuesHandlingConfiguration;

		private bool quoteNecessaryStrings;

		private bool quoteYaml1_1Strings;

		private ScalarStyle defaultScalarStyle;

		protected override StaticSerializerBuilder Self => this;

		public StaticSerializerBuilder(StaticContext context)
			: base((ITypeResolver)new DynamicTypeResolver())
		{
			this.context = context;
			factory = context.GetFactory();
			typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner));
			typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner);
			typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner));
			preProcessingPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> { 
			{
				typeof(AnchorAssigner),
				(IEnumerable<IYamlTypeConverter> typeConverters) => new AnchorAssigner(typeConverters)
			} };
			emissionPhaseObjectGraphVisitorFactories = new LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>>
			{
				{
					typeof(CustomSerializationObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new CustomSerializationObjectGraphVisitor(args.InnerVisitor, args.TypeConverters, args.NestedObjectSerializer)
				},
				{
					typeof(AnchorAssigningObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new AnchorAssigningObjectGraphVisitor(args.InnerVisitor, args.EventEmitter, args.GetPreProcessingPhaseObjectGraphVisitor<AnchorAssigner>())
				},
				{
					typeof(DefaultValuesObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new DefaultValuesObjectGraphVisitor(defaultValuesHandlingConfiguration, args.InnerVisitor, factory)
				},
				{
					typeof(CommentsObjectGraphVisitor),
					(EmissionPhaseObjectGraphVisitorArgs args) => new CommentsObjectGraphVisitor(args.InnerVisitor)
				}
			};
			eventEmitterFactories = new LazyComponentRegistrationList<IEventEmitter, IEventEmitter> { 
			{
				typeof(TypeAssigningEventEmitter),
				(IEventEmitter inner) => new TypeAssigningEventEmitter(inner, requireTagWhenStaticAndActualTypesAreDifferent: false, tagMappings, quoteNecessaryStrings, quoteYaml1_1Strings, defaultScalarStyle, yamlFormatter)
			} };
			objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable<IYamlTypeConverter> typeConverters, int maximumRecursion) => new FullObjectGraphTraversalStrategy(typeInspector, typeResolver, maximumRecursion, namingConvention, factory);
		}

		public StaticSerializerBuilder WithQuotingNecessaryStrings(bool quoteYaml1_1Strings = false)
		{
			quoteNecessaryStrings = true;
			this.quoteYaml1_1Strings = quoteYaml1_1Strings;
			return this;
		}

		public StaticSerializerBuilder WithQuotingNecessaryStrings()
		{
			quoteNecessaryStrings = true;
			return this;
		}

		public StaticSerializerBuilder WithDefaultScalarStyle(ScalarStyle style)
		{
			defaultScalarStyle = style;
			return this;
		}

		public StaticSerializerBuilder WithMaximumRecursion(int maximumRecursion)
		{
			if (maximumRecursion <= 0)
			{
				throw new ArgumentOutOfRangeException("maximumRecursion", $"The maximum recursion specified ({maximumRecursion}) is invalid. It should be a positive integer.");
			}
			this.maximumRecursion = maximumRecursion;
			return this;
		}

		public StaticSerializerBuilder WithEventEmitter<TEventEmitter>(Func<IEventEmitter, TEventEmitter> eventEmitterFactory) where TEventEmitter : IEventEmitter
		{
			return WithEventEmitter(eventEmitterFactory, delegate(IRegistrationLocationSelectionSyntax<IEventEmitter> w)
			{
				w.OnTop();
			});
		}

		public StaticSerializerBuilder WithEventEmitter<TEventEmitter>(Func<IEventEmitter, TEventEmitter> eventEmitterFactory, Action<IRegistrationLocationSelectionSyntax<IEventEmitter>> where) where TEventEmitter : IEventEmitter
		{
			if (eventEmitterFactory == null)
			{
				throw new ArgumentNullException("eventEmitterFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(eventEmitterFactories.CreateRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter inner) => eventEmitterFactory(inner)));
			return Self;
		}

		public StaticSerializerBuilder WithEventEmitter<TEventEmitter>(WrapperFactory<IEventEmitter, IEventEmitter, TEventEmitter> eventEmitterFactory, Action<ITrackingRegistrationLocationSelectionSyntax<IEventEmitter>> where) where TEventEmitter : IEventEmitter
		{
			if (eventEmitterFactory == null)
			{
				throw new ArgumentNullException("eventEmitterFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(eventEmitterFactories.CreateTrackingRegistrationLocationSelector(typeof(TEventEmitter), (IEventEmitter wrapped, IEventEmitter inner) => eventEmitterFactory(wrapped, inner)));
			return Self;
		}

		public StaticSerializerBuilder WithoutEventEmitter<TEventEmitter>() where TEventEmitter : IEventEmitter
		{
			return WithoutEventEmitter(typeof(TEventEmitter));
		}

		public StaticSerializerBuilder WithoutEventEmitter(Type eventEmitterType)
		{
			if (eventEmitterType == null)
			{
				throw new ArgumentNullException("eventEmitterType");
			}
			eventEmitterFactories.Remove(eventEmitterType);
			return this;
		}

		public override StaticSerializerBuilder WithTagMapping(TagName tag, Type type)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (tagMappings.TryGetValue(type, out var value))
			{
				throw new ArgumentException($"Type already has a registered tag '{value}' for type '{type.FullName}'", "type");
			}
			tagMappings.Add(type, tag);
			return this;
		}

		public StaticSerializerBuilder WithoutTagMapping(Type type)
		{
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (!tagMappings.Remove(type))
			{
				throw new KeyNotFoundException("Tag for type '" + type.FullName + "' is not registered");
			}
			return this;
		}

		public StaticSerializerBuilder EnsureRoundtrip()
		{
			objectGraphTraversalStrategyFactory = (ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable<IYamlTypeConverter> typeConverters, int maximumRecursion) => new RoundtripObjectGraphTraversalStrategy(typeConverters, typeInspector, typeResolver, maximumRecursion, namingConvention, settings, factory);
			WithEventEmitter((IEventEmitter inner) => new TypeAssigningEventEmitter(inner, requireTagWhenStaticAndActualTypesAreDifferent: true, tagMappings, quoteNecessaryStrings), delegate(IRegistrationLocationSelectionSyntax<IEventEmitter> loc)
			{
				loc.InsteadOf<TypeAssigningEventEmitter>();
			});
			return WithTypeInspector((ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner), delegate(IRegistrationLocationSelectionSyntax<ITypeInspector> loc)
			{
				loc.OnBottom();
			});
		}

		public StaticSerializerBuilder DisableAliases()
		{
			preProcessingPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigner));
			emissionPhaseObjectGraphVisitorFactories.Remove(typeof(AnchorAssigningObjectGraphVisitor));
			return this;
		}

		[Obsolete("The default behavior is now to always emit default values, thefore calling this method has no effect. This behavior is now controlled by ConfigureDefaultValuesHandling.", true)]
		public StaticSerializerBuilder EmitDefaults()
		{
			return ConfigureDefaultValuesHandling(DefaultValuesHandling.Preserve);
		}

		public StaticSerializerBuilder ConfigureDefaultValuesHandling(DefaultValuesHandling configuration)
		{
			defaultValuesHandlingConfiguration = configuration;
			return this;
		}

		public StaticSerializerBuilder JsonCompatible()
		{
			emitterSettings = emitterSettings.WithMaxSimpleKeyLength(int.MaxValue).WithoutAnchorName();
			return WithTypeConverter(new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: true), delegate(IRegistrationLocationSelectionSyntax<IYamlTypeConverter> w)
			{
				w.InsteadOf<YamlDotNet.Serialization.Converters.GuidConverter>();
			}).WithTypeConverter(new YamlDotNet.Serialization.Converters.DateTimeConverter(DateTimeKind.Utc, null, true)).WithEventEmitter((IEventEmitter inner) => new JsonEventEmitter(inner, yamlFormatter), delegate(IRegistrationLocationSelectionSyntax<IEventEmitter> loc)
			{
				loc.InsteadOf<TypeAssigningEventEmitter>();
			});
		}

		public StaticSerializerBuilder WithNewLine(string newLine)
		{
			emitterSettings = emitterSettings.WithNewLine(newLine);
			return this;
		}

		public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor<TObjectGraphVisitor>(TObjectGraphVisitor objectGraphVisitor) where TObjectGraphVisitor : IObjectGraphVisitor<Nothing>
		{
			return WithPreProcessingPhaseObjectGraphVisitor(objectGraphVisitor, delegate(IRegistrationLocationSelectionSyntax<IObjectGraphVisitor<Nothing>> w)
			{
				w.OnTop();
			});
		}

		public StaticSerializerBuilder WithPreProcessingPhaseObjectGraphVisitor<TObjectGraphVisitor>(TObjectGraphVisitor objectGraphVisitor, A