Decompiled source of Vanity v1.16.0

Vanity.dll

Decompiled 2 months 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.IO.Compression;
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.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using Service;
using TMPro;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
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: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Vanity")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a870dea9a7039e76f5cb933eee81d00882f12c98")]
[assembly: AssemblyProduct("Vanity")]
[assembly: AssemblyTitle("Vanity")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Service
{
	public class Watcher
	{
		private static readonly Dictionary<string, byte[]> hashes = new Dictionary<string, byte[]>();

		private static byte[] GetHash(string path)
		{
			using MD5 mD = MD5.Create();
			using FileStream inputStream = File.OpenRead(path);
			return mD.ComputeHash(inputStream);
		}

		public static void Setup(string folder, string pattern, Action action)
		{
			Action action2 = action;
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(folder, pattern);
			fileSystemWatcher.Changed += delegate(object s, FileSystemEventArgs e)
			{
				byte[] hash = GetHash(e.FullPath);
				if (!hashes.ContainsKey(e.FullPath) || !hashes[e.FullPath].SequenceEqual(hash))
				{
					hashes[e.FullPath] = hash;
					action2();
				}
			};
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		public static void Setup(string file, Action action)
		{
			string fileName = Path.GetFileName(file);
			Setup(Paths.ConfigPath, fileName, action);
		}

		public static void Setup(ConfigFile config, ManualLogSource logger)
		{
			ConfigFile config2 = config;
			ManualLogSource logger2 = logger;
			string configFilePath = config2.ConfigFilePath;
			string directoryName = Path.GetDirectoryName(configFilePath);
			string fileName = Path.GetFileName(configFilePath);
			Setup(directoryName, fileName, delegate
			{
				if (!File.Exists(config2.ConfigFilePath))
				{
					return;
				}
				try
				{
					logger2.LogDebug((object)"ReadConfigValues called");
					config2.Reload();
				}
				catch
				{
					logger2.LogError((object)("There was an issue loading your " + config2.ConfigFilePath));
					logger2.LogError((object)"Please check your config entries for spelling and format!");
				}
			});
		}
	}
}
namespace Vanity
{
	[HarmonyPatch(typeof(Player), "LateUpdate")]
	public class ColorCycle
	{
		private const float TickLength = 0.02f;

		private static int Ticks;

		private static int SecondsToTicks(float value)
		{
			return (int)(value / 0.02f);
		}

		private static Color GetColor(Color[] colors)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (colors.Length < 2)
			{
				return colors[0];
			}
			int num = SecondsToTicks(VanityManager.ColorDuration);
			if (num == 0)
			{
				return colors[0];
			}
			float num2 = (float)(Ticks % (num * colors.Length)) / (float)num;
			int num3 = (int)Math.Floor(num2);
			Color val = colors[num3];
			int num4 = (int)Math.Ceiling(num2);
			if (num4 >= colors.Length)
			{
				num4 = 0;
			}
			Color val2 = colors[num4];
			float num5 = num2 - (float)Math.Truncate(num2);
			return Color.Lerp(val, val2, num5);
		}

		private static void UpdateSkinColor(Player obj)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Color color = GetColor(VanityManager.GetSkinColors(obj));
			VanityManager.SkinColor = color;
			((Humanoid)obj).m_visEquipment.SetSkinColor(Vector3.zero);
		}

		private static void UpdateHairColor(Player obj)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Color color = GetColor(VanityManager.GetHairColors(obj));
			VanityManager.HairColor = color;
			((Humanoid)obj).m_visEquipment.SetHairColor(Vector3.zero);
		}

		private static void Postfix(Player __instance)
		{
			if (Helper.IsLocalPlayer(__instance))
			{
				Ticks++;
				int num = SecondsToTicks(VanityManager.ColorUpdateInterval);
				if (Ticks % num == 0)
				{
					UpdateSkinColor(__instance);
					UpdateHairColor(__instance);
				}
			}
		}
	}
	public class ChangeEquipment : MonoBehaviour
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__SetIntervalValue;

			public static ConsoleEvent <1>__SetDurationValue;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<string, bool> <>9__6_0;

			public static Func<string, bool> <>9__7_0;

			public static Func<string, bool> <>9__7_1;

			public static Func<int, List<string>> <>9__13_0;

			public static Func<int, List<string>> <>9__13_1;

			public static Func<int, List<string>> <>9__14_1;

			public static Func<int, List<string>> <>9__15_0;

			public static Func<int, List<string>> <>9__15_1;

			public static ConsoleOptionsFetcher <>9__16_1;

			public static ConsoleEvent <>9__17_0;

			public static ConsoleEvent <>9__17_1;

			public static ConsoleEvent <>9__17_2;

			public static ConsoleEvent <>9__17_3;

			public static ConsoleEvent <>9__17_4;

			public static ConsoleOptionsFetcher <>9__17_5;

			public static ConsoleEvent <>9__17_6;

			public static ConsoleOptionsFetcher <>9__17_7;

			public static ConsoleEvent <>9__17_8;

			public static ConsoleOptionsFetcher <>9__17_9;

			public static ConsoleEvent <>9__17_10;

			public static ConsoleOptionsFetcher <>9__17_11;

			public static ConsoleEvent <>9__17_12;

			public static ConsoleOptionsFetcher <>9__17_13;

			internal bool <AddPlayerId>b__6_0(string s)
			{
				return s.StartsWith("player=", StringComparison.OrdinalIgnoreCase);
			}

			internal bool <Parse>b__7_0(string s)
			{
				return s.StartsWith("player=", StringComparison.OrdinalIgnoreCase);
			}

			internal bool <Parse>b__7_1(string s)
			{
				return !s.StartsWith("player=", StringComparison.OrdinalIgnoreCase);
			}

			internal List<string> <RegisterGearAutoComplete>b__13_0(int index)
			{
				return index switch
				{
					0 => ObjectData.Items, 
					1 => ObjectData.Items, 
					2 => CommandWrapper.Info("Item variant (number)."), 
					_ => new List<string>(1) { "player" }, 
				};
			}

			internal List<string> <RegisterGearAutoComplete>b__13_1(int index)
			{
				if (index != 0)
				{
					return null;
				}
				return Helper.Players();
			}

			internal List<string> <RegisterAutoComplete>b__14_1(int index)
			{
				if (index != 0)
				{
					return null;
				}
				return Helper.Players();
			}

			internal List<string> <RegisterColorAutoComplete>b__15_0(int index)
			{
				return CommandWrapper.Info("Color (r,g,b)");
			}

			internal List<string> <RegisterColorAutoComplete>b__15_1(int index)
			{
				if (index != 0)
				{
					return null;
				}
				return Helper.Players();
			}

			internal List<string> <CreateCommand>b__16_1()
			{
				return ObjectData.Items;
			}

			internal void <AddChangeEquipment>b__17_0(ConsoleEventArgs args)
			{
				if (!((Object)(object)Player.m_localPlayer == (Object)null))
				{
					VisEquipment component = ((Component)Player.m_localPlayer).GetComponent<VisEquipment>();
					if (!((Object)(object)component == (Object)null))
					{
						args.Context.AddString("Helmet: " + component.m_helmetItem);
						args.Context.AddString("Shoulder: " + component.m_shoulderItem);
						args.Context.AddString("Chest: " + component.m_chestItem);
						args.Context.AddString("Leg: " + component.m_legItem);
						args.Context.AddString("Utility: " + component.m_utilityItem);
						args.Context.AddString("Left hand: " + component.m_leftItem);
						args.Context.AddString("Right hand: " + component.m_rightItem);
						args.Context.AddString("Left back: " + component.m_leftBackItem);
						args.Context.AddString("Right back: " + component.m_rightBackItem);
						args.Context.AddString("Hair: " + component.m_hairItem);
						args.Context.AddString("Beard: " + component.m_beardItem);
						args.Context.AddString("Skin: " + ((Vector3)(ref component.m_skinColor)).ToString("F2"));
						args.Context.AddString("Hair color: " + ((Vector3)(ref component.m_hairColor)).ToString("F2"));
					}
				}
			}

			internal void <AddChangeEquipment>b__17_1(ConsoleEventArgs args)
			{
				string[] args2 = AddPlayerId(args);
				if (Vanity.ConfigSync.IsSourceOfTruth)
				{
					Parse(args2, out string id);
					VanityEntry entry = GetEntry(id);
					Set(entry, (VisSlot)2, "");
					Set(entry, (VisSlot)3, "");
					Set(entry, (VisSlot)9, "");
					Set(entry, (VisSlot)4, "");
					Set(entry, (VisSlot)10, "");
					Set(entry, (VisSlot)0, "");
					Set(entry, (VisSlot)1, "");
					Set(entry, (VisSlot)6, "");
					Set(entry, (VisSlot)6, "");
					Set(entry, (VisSlot)5, "");
					Set(entry, (VisSlot)7, "");
					Set(entry, (VisSlot)8, "");
					Set(entry, (VisSlot)8, "");
					SetColor(entry, (VisSlot)10, "");
					SetColor(entry, (VisSlot)5, "");
					VanityData.ToFile();
				}
				else
				{
					ServerExecution.Send((IEnumerable<string>)args2);
				}
			}

			internal void <AddChangeEquipment>b__17_2(ConsoleEventArgs args)
			{
				SetColorValue((VisSlot)5, args);
			}

			internal void <AddChangeEquipment>b__17_3(ConsoleEventArgs args)
			{
				SetColorValue((VisSlot)10, args);
			}

			internal void <AddChangeEquipment>b__17_4(ConsoleEventArgs args)
			{
				SetVisualValue((VisSlot)9, args);
			}

			internal List<string> <AddChangeEquipment>b__17_5()
			{
				return ObjectData.Beards;
			}

			internal void <AddChangeEquipment>b__17_6(ConsoleEventArgs args)
			{
				SetVisualValue((VisSlot)10, args);
			}

			internal List<string> <AddChangeEquipment>b__17_7()
			{
				return ObjectData.Hairs;
			}

			internal void <AddChangeEquipment>b__17_8(ConsoleEventArgs args)
			{
				string[] args2 = AddPlayerId(args);
				string id;
				string[] array = Parse(args2, out id);
				if (array.Length < 2)
				{
					return;
				}
				VanityEntry entry = GetEntry(id);
				if (entry.gear.TryGetValue(array[1], out string value))
				{
					UndoCommands.Push(array[0] + " " + array[1] + " " + value);
				}
				else
				{
					UndoCommands.Push(array[0] + " " + array[1]);
				}
				if (Vanity.ConfigSync.IsSourceOfTruth)
				{
					if (array.Length == 2)
					{
						entry.gear.Remove(array[1]);
					}
					else
					{
						entry.gear[args[1]] = string.Join(" ", array.Skip(2));
					}
					VanityData.ToFile();
				}
				else
				{
					ServerExecution.Send((IEnumerable<string>)args2);
				}
			}

			internal List<string> <AddChangeEquipment>b__17_9()
			{
				return ObjectData.Items;
			}

			internal void <AddChangeEquipment>b__17_10(ConsoleEventArgs args)
			{
				string[] args2 = AddPlayerId(args);
				string id;
				string[] array = Parse(args2, out id);
				VanityEntry entry = GetEntry(id);
				if (entry.crafted.TryGetValue(array[1], out string value))
				{
					UndoCommands.Push(array[0] + " " + array[1] + " " + value);
				}
				else
				{
					UndoCommands.Push(array[0] + " " + array[1]);
				}
				if (Vanity.ConfigSync.IsSourceOfTruth)
				{
					entry.crafted[array[1]] = string.Join(" ", array.Skip(2));
					VanityData.ToFile();
				}
				else
				{
					ServerExecution.Send((IEnumerable<string>)args2);
				}
			}

			internal List<string> <AddChangeEquipment>b__17_11()
			{
				return ObjectData.Items;
			}

			internal void <AddChangeEquipment>b__17_12(ConsoleEventArgs args)
			{
				if (UndoCommands.Count == 0)
				{
					args.Context.AddString("Nothing to undo.");
					return;
				}
				string text = UndoCommands.Pop();
				args.Context.TryRunCommand(text, false, false);
				if (UndoCommands.Count > 0)
				{
					UndoCommands.Pop();
				}
			}

			internal List<string> <AddChangeEquipment>b__17_13()
			{
				return ObjectData.Items;
			}
		}

		private static readonly Stack<string> UndoCommands = new Stack<string>();

		private static string Get(VanityEntry entry, VisSlot slot)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			return (int)slot switch
			{
				2 => entry.leftBack, 
				3 => entry.rightBack, 
				9 => entry.beard, 
				4 => entry.chest, 
				10 => entry.hair, 
				0 => entry.leftHand, 
				1 => entry.rightHand, 
				6 => entry.helmet, 
				5 => entry.legs, 
				7 => entry.shoulder, 
				8 => entry.utility, 
				_ => throw new NotImplementedException(), 
			};
		}

		private static string GetColor(VanityEntry entry, VisSlot slot)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)slot != 5)
			{
				if ((int)slot == 10)
				{
					return entry.hairColor;
				}
				throw new NotImplementedException();
			}
			return entry.skinColor;
		}

		private static void Set(VanityEntry entry, VisSlot slot, string value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			switch ((int)slot)
			{
			case 2:
				entry.leftBack = value;
				break;
			case 3:
				entry.rightBack = value;
				break;
			case 9:
				entry.beard = value;
				break;
			case 4:
				entry.chest = value;
				break;
			case 10:
				entry.hair = value;
				break;
			case 0:
				entry.leftHand = value;
				break;
			case 1:
				entry.rightHand = value;
				break;
			case 6:
				entry.helmet = value;
				break;
			case 5:
				entry.legs = value;
				break;
			case 7:
				entry.shoulder = value;
				break;
			case 8:
				entry.utility = value;
				break;
			default:
				throw new NotImplementedException();
			}
		}

		private static void SetColor(VanityEntry entry, VisSlot slot, string value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)slot != 5)
			{
				if ((int)slot == 10)
				{
					entry.hairColor = value;
				}
			}
			else
			{
				entry.skinColor = value;
			}
		}

		private static VanityEntry GetEntry(string id)
		{
			VanityEntry vanityEntry = new VanityEntry();
			if (VanityData.Data.TryGetValue(id, out VanityEntry value))
			{
				vanityEntry = value;
			}
			else
			{
				VanityData.Data[id] = vanityEntry;
			}
			return vanityEntry;
		}

		private static string[] AddPlayerId(ConsoleEventArgs args)
		{
			if (string.IsNullOrEmpty(args.Args.FirstOrDefault((string s) => s.StartsWith("player=", StringComparison.OrdinalIgnoreCase))))
			{
				return args.Args.Append("player=" + Helper.GetPlayerID()).ToArray();
			}
			return args.Args;
		}

		private static string[] Parse(string[] args, out string id)
		{
			id = "";
			string text = args.FirstOrDefault((string s) => s.StartsWith("player=", StringComparison.OrdinalIgnoreCase));
			if (text == null)
			{
				return args;
			}
			string[] array = text.Split(new char[1] { '=' });
			string[] result = args.Where((string s) => !s.StartsWith("player=", StringComparison.OrdinalIgnoreCase)).ToArray();
			if (array.Length < 2)
			{
				throw new InvalidOperationException("Missing player id");
			}
			if (long.TryParse(array[1], out var result2))
			{
				id = result2.ToString();
				return result;
			}
			id = Helper.GetPlayerID(array[1]);
			return result;
		}

		private static void SetVisualValue(VisSlot slot, ConsoleEventArgs args)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			string[] args2 = AddPlayerId(args);
			string id;
			string[] array = Parse(args2, out id);
			string value = string.Join(" ", array.Skip(1));
			VanityEntry entry = GetEntry(id);
			string text = Get(entry, slot);
			UndoCommands.Push(array[0] + " " + text);
			if (Vanity.ConfigSync.IsSourceOfTruth)
			{
				Set(entry, slot, value);
				VanityData.ToFile();
			}
			else
			{
				ServerExecution.Send((IEnumerable<string>)args2);
			}
		}

		private static void SetColorValue(VisSlot slot, ConsoleEventArgs args)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			string[] args2 = AddPlayerId(args);
			string id;
			string[] array = Parse(args2, out id);
			string value = string.Join(" ", array.Skip(1)).Replace(", ", ",");
			VanityEntry entry = GetEntry(id);
			string color = GetColor(entry, slot);
			UndoCommands.Push(array[0] + " " + color);
			if (Vanity.ConfigSync.IsSourceOfTruth)
			{
				SetColor(entry, slot, value);
				VanityData.ToFile();
			}
			else
			{
				ServerExecution.Send((IEnumerable<string>)args2);
			}
		}

		private static void SetDurationValue(ConsoleEventArgs args)
		{
			string[] args2 = AddPlayerId(args);
			string id;
			string[] array = Parse(args2, out id);
			float value = Helper.TryFloat(string.Join(" ", array.Skip(1)));
			VanityEntry entry = GetEntry(id);
			Stack<string> undoCommands = UndoCommands;
			string obj = array[0];
			float? colorDuration = entry.colorDuration;
			undoCommands.Push(obj + " " + colorDuration);
			if (Vanity.ConfigSync.IsSourceOfTruth)
			{
				entry.colorDuration = value;
				VanityData.ToFile();
			}
			else
			{
				ServerExecution.Send((IEnumerable<string>)args2);
			}
		}

		private static void SetIntervalValue(ConsoleEventArgs args)
		{
			string[] args2 = AddPlayerId(args);
			string id;
			string[] array = Parse(args2, out id);
			float value = Helper.TryFloat(string.Join(" ", array.Skip(1)));
			VanityEntry entry = GetEntry(id);
			Stack<string> undoCommands = UndoCommands;
			string obj = array[0];
			float? updateInterval = entry.updateInterval;
			undoCommands.Push(obj + " " + updateInterval);
			if (Vanity.ConfigSync.IsSourceOfTruth)
			{
				entry.updateInterval = value;
				VanityData.ToFile();
			}
			else
			{
				ServerExecution.Send((IEnumerable<string>)args2);
			}
		}

		private static string SlotToString(VisSlot slot)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			return (int)slot switch
			{
				2 => "back_left", 
				3 => "back_right", 
				9 => "beard", 
				4 => "chest", 
				10 => "hair", 
				0 => "left", 
				1 => "right", 
				6 => "helmet", 
				5 => "legs", 
				7 => "shoulder", 
				8 => "utility", 
				_ => throw new NotImplementedException(), 
			};
		}

		private static void RegisterGearAutoComplete(string name)
		{
			CommandWrapper.Register(name, (int index) => index switch
			{
				0 => ObjectData.Items, 
				1 => ObjectData.Items, 
				2 => CommandWrapper.Info("Item variant (number)."), 
				_ => new List<string>(1) { "player" }, 
			}, new Dictionary<string, Func<int, List<string>>> { 
			{
				"player",
				(int index) => (index != 0) ? null : Helper.Players()
			} });
		}

		private static void RegisterAutoComplete(string name, bool variant = true)
		{
			CommandWrapper.Register(name, delegate(int index)
			{
				if (index == 0)
				{
					return ObjectData.Items;
				}
				return (index == 1 && variant) ? CommandWrapper.Info("Item variant (number).") : new List<string>(1) { "player" };
			}, new Dictionary<string, Func<int, List<string>>> { 
			{
				"player",
				(int index) => (index != 0) ? null : Helper.Players()
			} });
		}

		private static void RegisterColorAutoComplete(string name)
		{
			CommandWrapper.Register(name, (int index) => CommandWrapper.Info("Color (r,g,b)"), new Dictionary<string, Func<int, List<string>>> { 
			{
				"player",
				(int index) => (index != 0) ? null : Helper.Players()
			} });
		}

		private static void CreateCommand(VisSlot slot)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_007a: Expected O, but got Unknown
			//IL_0075: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			RegisterAutoComplete("wear_" + SlotToString(slot));
			string text = "wear_" + SlotToString(slot);
			ConsoleEvent val = delegate(ConsoleEventArgs args)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				SetVisualValue(slot, args);
			};
			object obj = <>c.<>9__16_1;
			if (obj == null)
			{
				ConsoleOptionsFetcher val2 = () => ObjectData.Items;
				<>c.<>9__16_1 = val2;
				obj = (object)val2;
			}
			new ConsoleCommand(text, "[item name] [variant = 0] - Changes visual equipment.", val, false, false, false, false, false, (ConsoleOptionsFetcher)obj, false, false, false);
		}

		public static void AddChangeEquipment()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_00ac: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00ee: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Expected O, but got Unknown
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Expected O, but got Unknown
			//IL_0210: 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_020d: Expected O, but got Unknown
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Expected O, but got Unknown
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Expected O, but got Unknown
			//IL_0294: 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_029f: Expected O, but got Unknown
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Expected O, but got Unknown
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Expected O, but got Unknown
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Expected O, but got Unknown
			object obj = <>c.<>9__17_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					if (!((Object)(object)Player.m_localPlayer == (Object)null))
					{
						VisEquipment component = ((Component)Player.m_localPlayer).GetComponent<VisEquipment>();
						if (!((Object)(object)component == (Object)null))
						{
							args.Context.AddString("Helmet: " + component.m_helmetItem);
							args.Context.AddString("Shoulder: " + component.m_shoulderItem);
							args.Context.AddString("Chest: " + component.m_chestItem);
							args.Context.AddString("Leg: " + component.m_legItem);
							args.Context.AddString("Utility: " + component.m_utilityItem);
							args.Context.AddString("Left hand: " + component.m_leftItem);
							args.Context.AddString("Right hand: " + component.m_rightItem);
							args.Context.AddString("Left back: " + component.m_leftBackItem);
							args.Context.AddString("Right back: " + component.m_rightBackItem);
							args.Context.AddString("Hair: " + component.m_hairItem);
							args.Context.AddString("Beard: " + component.m_beardItem);
							args.Context.AddString("Skin: " + ((Vector3)(ref component.m_skinColor)).ToString("F2"));
							args.Context.AddString("Hair color: " + ((Vector3)(ref component.m_hairColor)).ToString("F2"));
						}
					}
				};
				<>c.<>9__17_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("wear_info", "Prints information about visual equipment.", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__17_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate(ConsoleEventArgs args)
				{
					string[] args4 = AddPlayerId(args);
					if (Vanity.ConfigSync.IsSourceOfTruth)
					{
						Parse(args4, out string id3);
						VanityEntry entry3 = GetEntry(id3);
						Set(entry3, (VisSlot)2, "");
						Set(entry3, (VisSlot)3, "");
						Set(entry3, (VisSlot)9, "");
						Set(entry3, (VisSlot)4, "");
						Set(entry3, (VisSlot)10, "");
						Set(entry3, (VisSlot)0, "");
						Set(entry3, (VisSlot)1, "");
						Set(entry3, (VisSlot)6, "");
						Set(entry3, (VisSlot)6, "");
						Set(entry3, (VisSlot)5, "");
						Set(entry3, (VisSlot)7, "");
						Set(entry3, (VisSlot)8, "");
						Set(entry3, (VisSlot)8, "");
						SetColor(entry3, (VisSlot)10, "");
						SetColor(entry3, (VisSlot)5, "");
						VanityData.ToFile();
					}
					else
					{
						ServerExecution.Send((IEnumerable<string>)args4);
					}
				};
				<>c.<>9__17_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("wear_reset", "Resets visual equipment.", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			RegisterColorAutoComplete("wear_skin_color");
			object obj3 = <>c.<>9__17_2;
			if (obj3 == null)
			{
				ConsoleEvent val3 = delegate(ConsoleEventArgs args)
				{
					SetColorValue((VisSlot)5, args);
				};
				<>c.<>9__17_2 = val3;
				obj3 = (object)val3;
			}
			new ConsoleCommand("wear_skin_color", "[r1,g1,b1] [r2,g2,b2] ... - Changes skin color. Automatically cycles between multiple values.", (ConsoleEvent)obj3, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			RegisterColorAutoComplete("wear_hair_color");
			object obj4 = <>c.<>9__17_3;
			if (obj4 == null)
			{
				ConsoleEvent val4 = delegate(ConsoleEventArgs args)
				{
					SetColorValue((VisSlot)10, args);
				};
				<>c.<>9__17_3 = val4;
				obj4 = (object)val4;
			}
			new ConsoleCommand("wear_hair_color", "[r1,g1,b1] [r2,g2,b2] ... - Changes hair color. Automatically cycles between multiple values.", (ConsoleEvent)obj4, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			RegisterAutoComplete("wear_beard", variant: false);
			object obj5 = <>c.<>9__17_4;
			if (obj5 == null)
			{
				ConsoleEvent val5 = delegate(ConsoleEventArgs args)
				{
					SetVisualValue((VisSlot)9, args);
				};
				<>c.<>9__17_4 = val5;
				obj5 = (object)val5;
			}
			object obj6 = <>c.<>9__17_5;
			if (obj6 == null)
			{
				ConsoleOptionsFetcher val6 = () => ObjectData.Beards;
				<>c.<>9__17_5 = val6;
				obj6 = (object)val6;
			}
			new ConsoleCommand("wear_beard", "[name] - Changes beard.", (ConsoleEvent)obj5, false, false, false, false, false, (ConsoleOptionsFetcher)obj6, false, false, false);
			RegisterAutoComplete("wear_hair", variant: false);
			object obj7 = <>c.<>9__17_6;
			if (obj7 == null)
			{
				ConsoleEvent val7 = delegate(ConsoleEventArgs args)
				{
					SetVisualValue((VisSlot)10, args);
				};
				<>c.<>9__17_6 = val7;
				obj7 = (object)val7;
			}
			object obj8 = <>c.<>9__17_7;
			if (obj8 == null)
			{
				ConsoleOptionsFetcher val8 = () => ObjectData.Hairs;
				<>c.<>9__17_7 = val8;
				obj8 = (object)val8;
			}
			new ConsoleCommand("wear_hair", "[name] - Changes hair.", (ConsoleEvent)obj7, false, false, false, false, false, (ConsoleOptionsFetcher)obj8, false, false, false);
			RegisterGearAutoComplete("wear_gear");
			object obj9 = <>c.<>9__17_8;
			if (obj9 == null)
			{
				ConsoleEvent val9 = delegate(ConsoleEventArgs args)
				{
					string[] args3 = AddPlayerId(args);
					string id2;
					string[] array2 = Parse(args3, out id2);
					if (array2.Length >= 2)
					{
						VanityEntry entry2 = GetEntry(id2);
						if (entry2.gear.TryGetValue(array2[1], out string value2))
						{
							UndoCommands.Push(array2[0] + " " + array2[1] + " " + value2);
						}
						else
						{
							UndoCommands.Push(array2[0] + " " + array2[1]);
						}
						if (Vanity.ConfigSync.IsSourceOfTruth)
						{
							if (array2.Length == 2)
							{
								entry2.gear.Remove(array2[1]);
							}
							else
							{
								entry2.gear[args[1]] = string.Join(" ", array2.Skip(2));
							}
							VanityData.ToFile();
						}
						else
						{
							ServerExecution.Send((IEnumerable<string>)args3);
						}
					}
				};
				<>c.<>9__17_8 = val9;
				obj9 = (object)val9;
			}
			object obj10 = <>c.<>9__17_9;
			if (obj10 == null)
			{
				ConsoleOptionsFetcher val10 = () => ObjectData.Items;
				<>c.<>9__17_9 = val10;
				obj10 = (object)val10;
			}
			new ConsoleCommand("wear_gear", "[item name] [visual name] [variant = 0] - Changes visual of a specific gear.", (ConsoleEvent)obj9, false, false, false, false, false, (ConsoleOptionsFetcher)obj10, false, false, false);
			RegisterGearAutoComplete("wear_crafted");
			object obj11 = <>c.<>9__17_10;
			if (obj11 == null)
			{
				ConsoleEvent val11 = delegate(ConsoleEventArgs args)
				{
					string[] args2 = AddPlayerId(args);
					string id;
					string[] array = Parse(args2, out id);
					VanityEntry entry = GetEntry(id);
					if (entry.crafted.TryGetValue(array[1], out string value))
					{
						UndoCommands.Push(array[0] + " " + array[1] + " " + value);
					}
					else
					{
						UndoCommands.Push(array[0] + " " + array[1]);
					}
					if (Vanity.ConfigSync.IsSourceOfTruth)
					{
						entry.crafted[array[1]] = string.Join(" ", array.Skip(2));
						VanityData.ToFile();
					}
					else
					{
						ServerExecution.Send((IEnumerable<string>)args2);
					}
				};
				<>c.<>9__17_10 = val11;
				obj11 = (object)val11;
			}
			object obj12 = <>c.<>9__17_11;
			if (obj12 == null)
			{
				ConsoleOptionsFetcher val12 = () => ObjectData.Items;
				<>c.<>9__17_11 = val12;
				obj12 = (object)val12;
			}
			new ConsoleCommand("wear_crafted", "[item name] [visual name] [variant = 0] - Changes visual of a specific gear.", (ConsoleEvent)obj11, false, false, false, false, false, (ConsoleOptionsFetcher)obj12, false, false, false);
			object obj13 = <>c.<>9__17_12;
			if (obj13 == null)
			{
				ConsoleEvent val13 = delegate(ConsoleEventArgs args)
				{
					if (UndoCommands.Count == 0)
					{
						args.Context.AddString("Nothing to undo.");
					}
					else
					{
						string text = UndoCommands.Pop();
						args.Context.TryRunCommand(text, false, false);
						if (UndoCommands.Count > 0)
						{
							UndoCommands.Pop();
						}
					}
				};
				<>c.<>9__17_12 = val13;
				obj13 = (object)val13;
			}
			object obj14 = <>c.<>9__17_13;
			if (obj14 == null)
			{
				ConsoleOptionsFetcher val14 = () => ObjectData.Items;
				<>c.<>9__17_13 = val14;
				obj14 = (object)val14;
			}
			new ConsoleCommand("wear_undo", "Reverts wear commands.", (ConsoleEvent)obj13, false, false, false, false, false, (ConsoleOptionsFetcher)obj14, false, false, false);
			CreateCommand((VisSlot)2);
			CreateCommand((VisSlot)3);
			CreateCommand((VisSlot)4);
			CreateCommand((VisSlot)0);
			CreateCommand((VisSlot)1);
			CreateCommand((VisSlot)6);
			CreateCommand((VisSlot)5);
			CreateCommand((VisSlot)7);
			CreateCommand((VisSlot)8);
			object obj15 = <>O.<0>__SetIntervalValue;
			if (obj15 == null)
			{
				ConsoleEvent val15 = SetIntervalValue;
				<>O.<0>__SetIntervalValue = val15;
				obj15 = (object)val15;
			}
			new ConsoleCommand("wear_color_interval", "Sets the color update interval.", (ConsoleEvent)obj15, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj16 = <>O.<1>__SetDurationValue;
			if (obj16 == null)
			{
				ConsoleEvent val16 = SetDurationValue;
				<>O.<1>__SetDurationValue = val16;
				obj16 = (object)val16;
			}
			new ConsoleCommand("wear_color_duration", "Sets the color duration.", (ConsoleEvent)obj16, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
	}
	public static class CommandWrapper
	{
		public static Assembly ServerDevcommands = null;

		private const string GUID = "server_devcommands";

		private static readonly BindingFlags PublicBinding = BindingFlags.Static | BindingFlags.Public;

		public static void Init()
		{
			if (Chainloader.PluginInfos.TryGetValue("server_devcommands", out var value))
			{
				ServerDevcommands = ((object)value.Instance).GetType().Assembly;
			}
		}

		private static Type Type()
		{
			return ServerDevcommands.GetType("ServerDevcommands.AutoComplete");
		}

		private static Type InfoType()
		{
			return ServerDevcommands.GetType("ServerDevcommands.ParameterInfo");
		}

		private static MethodInfo GetMethod(Type type, string name, Type[] types)
		{
			return type.GetMethod(name, PublicBinding, null, CallingConventions.Standard, types, null);
		}

		public static void Register(string command, Func<int, int, List<string>> action)
		{
			if (!(ServerDevcommands == null))
			{
				GetMethod(Type(), "Register", new Type[2]
				{
					typeof(string),
					typeof(Func<int, int, List<string>>)
				}).Invoke(null, new object[2] { command, action });
			}
		}

		public static void Register(string command, Func<int, List<string>> action)
		{
			if (!(ServerDevcommands == null))
			{
				GetMethod(Type(), "Register", new Type[2]
				{
					typeof(string),
					typeof(Func<int, List<string>>)
				}).Invoke(null, new object[2] { command, action });
			}
		}

		public static void Register(string command, Func<int, List<string>> action, Dictionary<string, Func<int, List<string>>> named)
		{
			if (!(ServerDevcommands == null))
			{
				GetMethod(Type(), "Register", new Type[3]
				{
					typeof(string),
					typeof(Func<int, List<string>>),
					typeof(Dictionary<string, Func<int, List<string>>>)
				}).Invoke(null, new object[3] { command, action, named });
			}
		}

		public static List<string> Info(string value)
		{
			if (ServerDevcommands == null)
			{
				return new List<string>();
			}
			return GetMethod(InfoType(), "Create", new Type[1] { typeof(string) }).Invoke(null, new object[1] { value }) as List<string>;
		}

		public static List<string> XZ(string name, string description, int index)
		{
			if (ServerDevcommands == null)
			{
				return new List<string>();
			}
			return GetMethod(InfoType(), "XZ", new Type[3]
			{
				typeof(string),
				typeof(string),
				typeof(int)
			}).Invoke(null, new object[3] { name, description, index }) as List<string>;
		}

		public static List<string> Flag(string name, string description)
		{
			if (ServerDevcommands == null)
			{
				return new List<string>();
			}
			return GetMethod(InfoType(), "Flag", new Type[2]
			{
				typeof(string),
				typeof(string)
			}).Invoke(null, new object[2] { name, description }) as List<string>;
		}

		public static List<string> ObjectIds()
		{
			if (ServerDevcommands == null)
			{
				return new List<string>();
			}
			return InfoType().GetProperty("ObjectIds", PublicBinding).GetValue(null) as List<string>;
		}

		public static List<string> LocationIds()
		{
			if (ServerDevcommands == null)
			{
				return new List<string>();
			}
			return InfoType().GetProperty("LocationIds", PublicBinding).GetValue(null) as List<string>;
		}

		public static void RegisterEmpty(string command)
		{
			if (!(ServerDevcommands == null))
			{
				MethodInfo? method = Type().GetMethod("RegisterEmpty", PublicBinding);
				object[] parameters = new string[1] { command };
				method.Invoke(null, parameters);
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	public class ObjectDB_Awake
	{
		private static void Postfix(ObjectDB __instance)
		{
			ObjectData.Beards = (from item in __instance.GetAllItems((ItemType)10, "Beard")
				select ((Object)item).name).ToList();
			ObjectData.Hairs = (from item in __instance.GetAllItems((ItemType)10, "Hair")
				select ((Object)item).name).ToList();
			ObjectData.Items = __instance.m_items.Select((GameObject item) => ((Object)item).name).ToList();
		}
	}
	public class ObjectData
	{
		public static List<string> Beards = new List<string>();

		public static List<string> Hairs = new List<string>();

		public static List<string> Items = new List<string>();
	}
	public class VanityEntry
	{
		[DefaultValue("")]
		public string name = "";

		[DefaultValue("")]
		public string player = "";

		[DefaultValue("")]
		public string group = "";

		[DefaultValue("")]
		public string helmet = "";

		[DefaultValue("")]
		public string chest = "";

		[DefaultValue("")]
		public string shoulder = "";

		[DefaultValue("")]
		public string legs = "";

		[DefaultValue("")]
		public string utility = "";

		[DefaultValue("")]
		public string leftHand = "";

		[DefaultValue("")]
		public string rightHand = "";

		[DefaultValue("")]
		public string leftBack = "";

		[DefaultValue("")]
		public string rightBack = "";

		[DefaultValue("")]
		public string beard = "";

		[DefaultValue("")]
		public string hair = "";

		[DefaultValue("")]
		public string skinColor = "";

		[DefaultValue("")]
		public string hairColor = "";

		[DefaultValue(null)]
		public float? updateInterval;

		[DefaultValue(null)]
		public float? colorDuration;

		public Dictionary<string, string> gear = new Dictionary<string, string>();

		public Dictionary<string, string> crafted = new Dictionary<string, string>();
	}
	public class VanityInfo
	{
		public Dictionary<string, Tuple<string, int>> gear = new Dictionary<string, Tuple<string, int>>();

		public Tuple<string, int>? helmet;

		public Tuple<string, int>? chest;

		public Tuple<string, int>? legs;

		public Tuple<string, int>? shoulder;

		public Tuple<string, int>? utility;

		public Tuple<string, int>? leftHand;

		public Tuple<string, int>? rightHand;

		public Tuple<string, int>? leftBack;

		public Tuple<string, int>? rightBack;

		public Tuple<string, int>? beard;

		public Tuple<string, int>? hair;

		public string skinColor = "";

		public string hairColor = "";

		public float? updateInterval;

		public float? colorDuration;
	}
	public class VanityData
	{
		public static Dictionary<string, VanityEntry> Data = new Dictionary<string, VanityEntry>();

		public static Dictionary<string, string> PlayerIds = new Dictionary<string, string>();

		public static string FileName = "vanity.yaml";

		public static string FilePath = Path.Combine(Paths.ConfigPath, FileName);

		public static void CreateFile()
		{
			if (!File.Exists(FilePath))
			{
				File.WriteAllText(FilePath, "");
			}
		}

		public static void ToFile()
		{
			if (Vanity.ConfigSync.IsSourceOfTruth)
			{
				string contents = Serializer().Serialize(Data);
				File.WriteAllText(FilePath, contents);
			}
		}

		public static void FromFile()
		{
			if (Vanity.ConfigSync.IsSourceOfTruth)
			{
				Vanity.VanityValue.Value = File.ReadAllText(FilePath);
			}
		}

		public static void FromValue(string value)
		{
			Data = Deserialize<Dictionary<string, VanityEntry>>(value, "Data") ?? new Dictionary<string, VanityEntry>();
			PlayerIds.Clear();
			foreach (KeyValuePair<string, VanityEntry> datum in Data)
			{
				if (!string.IsNullOrEmpty(datum.Value.name))
				{
					PlayerIds[datum.Value.name] = datum.Key;
				}
			}
			VanityManager.Load();
			Vanity.Log.LogInfo((object)$"Reloading {Data.Count} vanity data.");
		}

		public static void SetupWatcher()
		{
			Watcher.Setup(FileName, FromFile);
		}

		public static IDeserializer Deserializer()
		{
			return new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).WithTypeConverter(new FloatConverter()).Build();
		}

		public static IDeserializer DeserializerUnSafe()
		{
			return new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).WithTypeConverter(new FloatConverter()).IgnoreUnmatchedProperties()
				.Build();
		}

		public static ISerializer Serializer()
		{
			return new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).DisableAliases().ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults)
				.WithTypeConverter(new FloatConverter())
				.Build();
		}

		public static T Deserialize<T>(string raw, string fileName) where T : new()
		{
			try
			{
				return Deserializer().Deserialize<T>(raw);
			}
			catch (Exception ex)
			{
				Vanity.Log.LogError((object)(fileName + ": " + ex.Message));
				try
				{
					return DeserializerUnSafe().Deserialize<T>(raw);
				}
				catch (Exception)
				{
					return new T();
				}
			}
		}

		public static Dictionary<long, T> Read<T>(string pattern)
		{
			Dictionary<long, T> dictionary = new Dictionary<long, T>();
			string[] files = Directory.GetFiles(Paths.ConfigPath, pattern);
			foreach (string text in files)
			{
				Dictionary<long, T> dictionary2 = Deserialize<Dictionary<long, T>>(File.ReadAllText(text), text);
				if (dictionary2 == null)
				{
					continue;
				}
				foreach (KeyValuePair<long, T> item in dictionary2)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			return dictionary;
		}

		private static bool UpdateName(string id, string name)
		{
			if (Data.TryGetValue(id, out VanityEntry value))
			{
				if (value.name == name)
				{
					return false;
				}
				value.name = name;
				return true;
			}
			Data[id] = new VanityEntry
			{
				name = name
			};
			return true;
		}

		private static bool UpdateNetworkId(string id, string networkId)
		{
			if (Data.TryGetValue(id, out VanityEntry value))
			{
				if (value.player == networkId)
				{
					return false;
				}
				value.player = networkId;
				return true;
			}
			Data[id] = new VanityEntry
			{
				player = networkId
			};
			return true;
		}

		public static void UpdatePlayerIds()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			if (instance == null || !Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
			{
				return;
			}
			bool flag = false;
			flag |= UpdateName("Everyone", "Everyone");
			if (!ZNet.instance.IsDedicated())
			{
				flag |= UpdateName(Game.instance.GetPlayerProfile().GetPlayerID().ToString(), Game.instance.GetPlayerProfile().GetName());
				flag |= UpdateNetworkId(Game.instance.GetPlayerProfile().GetPlayerID().ToString(), Helper.GetNetworkId());
			}
			foreach (ZDOPeer peer in instance.m_peers)
			{
				ZDO zDO = instance.GetZDO(peer.m_peer.m_characterID);
				if (zDO == null)
				{
					return;
				}
				long @long = zDO.GetLong(ZDOVars.s_playerID, 0L);
				string @string = zDO.GetString(ZDOVars.s_playerName, "");
				if (@long != 0L && !(@string == ""))
				{
					flag |= UpdateName(@long.ToString(), @string);
					flag |= UpdateNetworkId(@long.ToString(), peer.m_peer.m_rpc.GetSocket().GetHostName());
				}
			}
			if (flag)
			{
				ToFile();
			}
		}
	}
	public class FloatConverter : IYamlTypeConverter
	{
		public bool Accepts(Type type)
		{
			return type == typeof(float);
		}

		public object ReadYaml(IParser parser, Type type)
		{
			float num = float.Parse(((YamlDotNet.Core.Events.Scalar)parser.Current).Value, NumberStyles.Float, CultureInfo.InvariantCulture);
			parser.MoveNext();
			return num;
		}

		public void WriteYaml(IEmitter emitter, object value, Type type)
		{
			emitter.Emit(new YamlDotNet.Core.Events.Scalar(((float)value).ToString("0.###", CultureInfo.InvariantCulture)));
		}
	}
	public class VanityManager
	{
		public static VanityInfo Info = new VanityInfo();

		public static Dictionary<string, Dictionary<string, Tuple<string, int>>> Crafted = new Dictionary<string, Dictionary<string, Tuple<string, int>>>();

		public static Color? SkinColor;

		public static Color? HairColor;

		public static float ColorUpdateInterval => Info.updateInterval.GetValueOrDefault(0.1f);

		public static float ColorDuration => Info.colorDuration.GetValueOrDefault(1f);

		public static void Load()
		{
			Info = new VanityInfo();
			LoadCrafted();
			string playerID = Helper.GetPlayerID();
			string networkId = Helper.GetNetworkId();
			Load(Info, "Everyone");
			Load(Info, "0");
			Load(Info, networkId);
			Load(Info, playerID);
			if (Object.op_Implicit((Object)(object)Game.instance) && Game.instance.m_shuttingDown)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)FejdStartup.m_instance) && Object.op_Implicit((Object)(object)FejdStartup.m_instance.m_playerInstance))
			{
				Player component = FejdStartup.m_instance.m_playerInstance.GetComponent<Player>();
				if (component != null)
				{
					((Humanoid)component).SetupEquipment();
				}
			}
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Humanoid)Player.m_localPlayer).SetupEquipment();
			}
		}

		private static void LoadCrafted()
		{
			Crafted = new Dictionary<string, Dictionary<string, Tuple<string, int>>>();
			foreach (KeyValuePair<string, VanityEntry> datum in VanityData.Data)
			{
				if (!Crafted.ContainsKey(datum.Key))
				{
					Crafted[datum.Key] = new Dictionary<string, Tuple<string, int>>();
				}
				foreach (KeyValuePair<string, string> item in datum.Value.crafted)
				{
					Crafted[datum.Key][item.Key] = Helper.Parse(item.Value);
				}
			}
		}

		private static void Load(VanityInfo info, string id)
		{
			if (!VanityData.Data.TryGetValue(id, out VanityEntry value))
			{
				return;
			}
			if (!string.IsNullOrEmpty(value.group))
			{
				string[] array = Helper.ParseGroups(value.group);
				foreach (string id2 in array)
				{
					Load(info, id2);
				}
			}
			if (!string.IsNullOrEmpty(value.beard))
			{
				info.beard = Helper.Parse(value.beard);
			}
			if (!string.IsNullOrEmpty(value.chest))
			{
				info.chest = Helper.Parse(value.chest);
			}
			if (value.colorDuration.HasValue)
			{
				info.colorDuration = value.colorDuration;
			}
			if (!string.IsNullOrEmpty(value.hair))
			{
				info.hair = Helper.Parse(value.hair);
			}
			if (!string.IsNullOrEmpty(value.hairColor))
			{
				info.hairColor = value.hairColor;
			}
			if (!string.IsNullOrEmpty(value.helmet))
			{
				info.helmet = Helper.Parse(value.helmet);
			}
			if (!string.IsNullOrEmpty(value.leftBack))
			{
				info.leftBack = Helper.Parse(value.leftBack);
			}
			if (!string.IsNullOrEmpty(value.leftHand))
			{
				info.leftHand = Helper.Parse(value.leftHand);
			}
			if (!string.IsNullOrEmpty(value.legs))
			{
				info.legs = Helper.Parse(value.legs);
			}
			if (!string.IsNullOrEmpty(value.rightBack))
			{
				info.rightBack = Helper.Parse(value.rightBack);
			}
			if (!string.IsNullOrEmpty(value.rightHand))
			{
				info.rightHand = Helper.Parse(value.rightHand);
			}
			if (!string.IsNullOrEmpty(value.shoulder))
			{
				info.shoulder = Helper.Parse(value.shoulder);
			}
			if (!string.IsNullOrEmpty(value.skinColor))
			{
				info.skinColor = value.skinColor;
			}
			if (value.updateInterval.HasValue)
			{
				info.updateInterval = value.updateInterval;
			}
			if (!string.IsNullOrEmpty(value.utility))
			{
				info.utility = Helper.Parse(value.utility);
			}
			foreach (KeyValuePair<string, string> item in value.gear)
			{
				info.gear[item.Key] = Helper.Parse(item.Value);
			}
		}

		public static Tuple<string, int>? GetVisualBySlot(VisSlot slot)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			return (int)slot switch
			{
				2 => Info.leftBack, 
				3 => Info.rightBack, 
				9 => Info.beard, 
				4 => Info.chest, 
				10 => Info.hair, 
				0 => Info.leftHand, 
				1 => Info.rightHand, 
				6 => Info.helmet, 
				5 => Info.legs, 
				7 => Info.shoulder, 
				8 => Info.utility, 
				_ => null, 
			};
		}

		public static Color[] GetSkinColors(Player obj)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return Helper.ParseColors(Info.skinColor, obj.m_skinColor);
		}

		public static Color[] GetHairColors(Player obj)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return Helper.ParseColors(Info.hairColor, obj.m_hairColor);
		}

		private static ItemData? GetEquipment(Player player, VisSlot slot)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			return (ItemData?)((int)slot switch
			{
				2 => ((Humanoid)player).m_leftItem, 
				3 => ((Humanoid)player).m_rightItem, 
				9 => null, 
				4 => ((Humanoid)player).m_chestItem, 
				10 => null, 
				0 => ((Humanoid)player).m_leftItem, 
				1 => ((Humanoid)player).m_rightItem, 
				6 => ((Humanoid)player).m_helmetItem, 
				5 => ((Humanoid)player).m_legItem, 
				7 => ((Humanoid)player).m_shoulderItem, 
				8 => ((Humanoid)player).m_utilityItem, 
				_ => throw new NotImplementedException(), 
			});
		}

		public static void OverrideItem(VisEquipment vis, VisSlot slot, ref string name, ref int variant)
		{
			//IL_000f: 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)
			if (Helper.IsLocalPlayer(vis))
			{
				ItemData equipment = GetEquipment(((Component)vis).GetComponent<Player>(), slot);
				Tuple<string, int> visualBySlot = GetVisualBySlot(slot);
				Dictionary<string, Tuple<string, int>> value;
				Tuple<string, int> value2;
				Tuple<string, int> value3;
				if (visualBySlot != null)
				{
					name = visualBySlot.Item1;
					variant = visualBySlot.Item2;
				}
				else if (equipment != null && Crafted.TryGetValue(equipment.m_crafterID.ToString(), out value) && value.TryGetValue(name, out value2))
				{
					name = value2.Item1;
					variant = value2.Item2;
				}
				else if (Info.gear.TryGetValue(name, out value3))
				{
					name = value3.Item1;
					variant = value3.Item2;
				}
			}
		}

		private static VisSlot? GetSlot(ItemData item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected I4, but got Unknown
			ItemType itemType = item.m_shared.m_itemType;
			return (itemType - 3) switch
			{
				0 => (VisSlot)1, 
				1 => (VisSlot)0, 
				4 => (VisSlot)4, 
				3 => (VisSlot)6, 
				8 => (VisSlot)5, 
				2 => (VisSlot)0, 
				16 => (VisSlot)1, 
				14 => (VisSlot)7, 
				12 => (VisSlot)1, 
				11 => (VisSlot)1, 
				15 => (VisSlot)8, 
				_ => null, 
			};
		}

		public static void OverrideItem(ItemData item, ref string name, ref int variant)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			VisSlot? slot = GetSlot(item);
			if (slot.HasValue)
			{
				Tuple<string, int> visualBySlot = GetVisualBySlot(slot.Value);
				Dictionary<string, Tuple<string, int>> value;
				Tuple<string, int> value2;
				Tuple<string, int> value3;
				if (visualBySlot != null)
				{
					name = visualBySlot.Item1;
					variant = visualBySlot.Item2;
				}
				else if (Crafted.TryGetValue(item.m_crafterID.ToString(), out value) && Object.op_Implicit((Object)(object)item.m_dropPrefab) && value.TryGetValue(((Object)item.m_dropPrefab).name, out value2))
				{
					name = value2.Item1;
					variant = value2.Item2;
				}
				else if (Object.op_Implicit((Object)(object)item.m_dropPrefab) && Info.gear.TryGetValue(((Object)item.m_dropPrefab).name, out value3))
				{
					name = value3.Item1;
					variant = value3.Item2;
				}
			}
		}

		public static void OverrideItem(VisEquipment vis, VisSlot slot, ref string name)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			int variant = 0;
			OverrideItem(vis, slot, ref name, ref variant);
		}

		public static void OverrideSkinColor(VisEquipment vis, ref Vector3 color)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (Helper.IsLocalPlayer(vis) && SkinColor.HasValue)
			{
				color.x = SkinColor.Value.r;
				color.y = SkinColor.Value.g;
				color.z = SkinColor.Value.b;
			}
		}

		public static void OverrideHairColor(VisEquipment vis, ref Vector3 color)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (Helper.IsLocalPlayer(vis) && HairColor.HasValue)
			{
				color.x = HairColor.Value.r;
				color.y = HairColor.Value.g;
				color.z = HairColor.Value.b;
			}
		}
	}
	public static class Helper
	{
		public static List<string> Players()
		{
			return (from s in VanityData.PlayerIds.Keys
				select s.Replace(" ", "_") into s
				orderby s
				select s).ToList();
		}

		private static string Normalize(string name)
		{
			return name.ToLower().Replace(" ", "_");
		}

		public static string GetPlayerID(string name)
		{
			string name2 = name;
			name2 = name2.ToLower().Replace(" ", "_");
			Dictionary<string, string> dictionary = VanityData.PlayerIds.ToDictionary<KeyValuePair<string, string>, string, string>((KeyValuePair<string, string> kvp) => Normalize(kvp.Key), (KeyValuePair<string, string> kvp) => kvp.Value);
			if (dictionary.TryGetValue(name2, out var value))
			{
				return value;
			}
			string text = dictionary.Keys.FirstOrDefault((string s) => s.StartsWith(name2, StringComparison.OrdinalIgnoreCase));
			if (!string.IsNullOrEmpty(text))
			{
				return dictionary[text];
			}
			text = dictionary.Keys.FirstOrDefault((string s) => s.Contains(name2));
			if (!string.IsNullOrEmpty(text))
			{
				return dictionary[text];
			}
			throw new InvalidOperationException("Unable to find the player.");
		}

		public static bool IsLocalPlayer(VisEquipment obj)
		{
			if (Object.op_Implicit((Object)(object)obj) && obj.m_isPlayer)
			{
				return IsLocalPlayer(((Component)obj).GetComponent<Player>());
			}
			return false;
		}

		public static bool IsLocalPlayer(Player obj)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)obj))
			{
				if (!((Object)(object)obj == (Object)(object)Player.m_localPlayer))
				{
					return ((Character)obj).GetZDOID() == ZDOID.None;
				}
				return true;
			}
			return false;
		}

		public static bool IsTrophy(ItemData item)
		{
			if (item != null)
			{
				return Name(item).ToLower().Contains("trophy");
			}
			return false;
		}

		public static string Name(ItemData item)
		{
			object obj;
			if (item == null)
			{
				obj = null;
			}
			else
			{
				GameObject dropPrefab = item.m_dropPrefab;
				obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			}
			if (obj == null)
			{
				obj = "";
			}
			return (string)obj;
		}

		public static float TryFloat(string arg, float defaultValue = 1f)
		{
			if (!float.TryParse(arg, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return defaultValue;
			}
			return result;
		}

		public static float TryFloat(string[] args, int index, float defaultValue = 1f)
		{
			if (index >= args.Length)
			{
				return defaultValue;
			}
			return TryFloat(args[index], defaultValue);
		}

		public static int TryInt(string arg, int defaultValue = 1)
		{
			if (!int.TryParse(arg, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return defaultValue;
			}
			return result;
		}

		public static int TryInt(string[] args, int index, int defaultValue = 1)
		{
			if (index >= args.Length)
			{
				return defaultValue;
			}
			return TryInt(args[index], defaultValue);
		}

		public static Tuple<string, int> Parse(string value)
		{
			char[] separator = new char[2] { ',', ' ' };
			string[] array = value.Split(separator, StringSplitOptions.RemoveEmptyEntries).ToArray();
			string item = array[0];
			int item2 = TryInt(array, 1, 0);
			return new Tuple<string, int>(item, item2);
		}

		public static string[] ParseGroups(string value)
		{
			char[] separator = new char[2] { ',', ' ' };
			return value.Split(separator, StringSplitOptions.RemoveEmptyEntries).ToArray();
		}

		public static Color ParseColor(string value, Color baseColor)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			string[] args = value.Split(new char[1] { ',' });
			Color val = baseColor;
			val.r = TryFloat(args, 0, val.r);
			val.g = TryFloat(args, 1, val.g);
			val.b = TryFloat(args, 2, val.b);
			return val;
		}

		public static Color[] ParseColors(string value, Vector3 baseColor)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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)
			string[] source = value.Split(new char[1] { ' ' });
			Color color = new Color(baseColor.x, baseColor.y, baseColor.z);
			return source.Select((string value) => ParseColor(value, color)).ToArray();
		}

		public static string GetPlayerID()
		{
			Player localPlayer = Player.m_localPlayer;
			return ((localPlayer != null) ? localPlayer.GetPlayerID().ToString() : null) ?? CharacterPreview.Id;
		}

		public static string GetNetworkId()
		{
			object obj;
			if (PrivilegeManager.privilegeData.HasValue)
			{
				obj = PrivilegeManager.PlatformUserId;
				if (obj == null)
				{
					return "0";
				}
			}
			else
			{
				obj = "0";
			}
			return (string)obj;
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "SetupCharacterPreview")]
	public class CharacterPreview
	{
		public static string Id = "";

		private static void Prefix(PlayerProfile profile)
		{
			if (profile == null)
			{
				Id = "";
			}
			else
			{
				Id = profile.m_playerID.ToString();
			}
			VanityManager.Load();
		}
	}
	[HarmonyPatch(typeof(Player), "Awake")]
	public class LoadVanity
	{
		private static void Postfix()
		{
			VanityManager.Load();
		}
	}
	[HarmonyPatch]
	public class IconPatches
	{
		private static Sprite? OverrideItem(ItemData item)
		{
			string name = "";
			int variant = 0;
			VanityManager.OverrideItem(item, ref name, ref variant);
			if (name == "")
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name);
			ItemData val = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData);
			if (val == null || val.m_shared.m_icons == null || val.m_shared.m_icons.Length <= variant)
			{
				return null;
			}
			return val.m_shared.m_icons[variant];
		}

		[HarmonyPatch(typeof(ItemData), "GetIcon")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static Sprite GetIcon(Sprite result, ItemData __instance)
		{
			return OverrideItem(__instance) ?? result;
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupUpgradeItem")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void SetupUpgradeItem(InventoryGui __instance, Recipe recipe, ItemData item)
		{
			if (item == null)
			{
				item = recipe.m_item.m_itemData;
			}
			__instance.m_upgradeItemIcon.sprite = OverrideItem(item) ?? __instance.m_upgradeItemIcon.sprite;
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void UpdateRecipe(InventoryGui __instance)
		{
			ItemData itemData = ((RecipeDataPair)(ref __instance.m_selectedRecipe)).ItemData;
			if (itemData != null)
			{
				__instance.m_recipeIcon.sprite = OverrideItem(itemData) ?? __instance.m_recipeIcon.sprite;
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(string) })]
	public class RedirectOutput
	{
		public static ZRpc? Target;

		private static void Postfix(string text)
		{
			if (ZNet.m_isServer && Target != null)
			{
				ZNet.instance.RemotePrint(Target, text);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	public class ServerExecution
	{
		public static string RPC_Command = "VANITY_Command";

		public static void Send(string command)
		{
			ZRpc serverRPC = ZNet.instance.GetServerRPC();
			((Terminal)Console.instance).AddString("Sending command: " + command);
			if (serverRPC != null)
			{
				string rPC_Command = RPC_Command;
				object[] array = new string[1] { command };
				serverRPC.Invoke(rPC_Command, array);
			}
		}

		public static void Send(IEnumerable<string> args)
		{
			Send(string.Join(" ", args));
		}

		public static void Send(ConsoleEventArgs args)
		{
			Send((IEnumerable<string>)args.Args);
		}

		private static bool IsAllowed(ZRpc rpc)
		{
			ZNet instance = ZNet.instance;
			if (!((Behaviour)instance).enabled)
			{
				return false;
			}
			if (rpc != null && !instance.ListContainsId(instance.m_adminList, rpc.GetSocket().GetHostName()))
			{
				((Terminal)Console.instance).AddString("Unauthorized to set vanity.");
				return false;
			}
			return true;
		}

		private static void RPC_Do_Command(ZRpc rpc, string command)
		{
			RedirectOutput.Target = rpc;
			if (IsAllowed(rpc))
			{
				((Terminal)Console.instance).TryRunCommand(command, false, false);
			}
			RedirectOutput.Target = null;
		}

		private static void Postfix(ZNet __instance, ZRpc rpc)
		{
			if (__instance.IsServer())
			{
				rpc.Register<string>(RPC_Command, (Action<ZRpc, string>)RPC_Do_Command);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "SetupVisEquipment")]
	public class SetupVisEquipment
	{
		private static void Prefix(Humanoid __instance)
		{
			SetEquipment.IsHidden = __instance.m_hiddenLeftItem != null || __instance.m_hiddenRightItem != null;
		}
	}
	[HarmonyPatch(typeof(VisEquipment))]
	[HarmonyPriority(200)]
	public class SetEquipment
	{
		public static bool IsHidden;

		[HarmonyPatch("SetRightItem")]
		[HarmonyPrefix]
		private static void SetRightItem(VisEquipment __instance, ref string name)
		{
			if (!IsHidden)
			{
				VanityManager.OverrideItem(__instance, (VisSlot)1, ref name);
			}
		}

		[HarmonyPatch("SetLeftItem")]
		[HarmonyPrefix]
		private static void SetLeftItem(VisEquipment __instance, ref string name, ref int variant)
		{
			if (!IsHidden)
			{
				VanityManager.OverrideItem(__instance, (VisSlot)0, ref name, ref variant);
			}
		}

		[HarmonyPatch("SetRightBackItem")]
		[HarmonyPrefix]
		private static void SetRightBackItem(VisEquipment __instance, ref string name)
		{
			if (IsHidden)
			{
				VanityManager.OverrideItem(__instance, (VisSlot)1, ref name);
			}
			VanityManager.OverrideItem(__instance, (VisSlot)3, ref name);
		}

		[HarmonyPatch("SetLeftBackItem")]
		[HarmonyPrefix]
		private static void SetLeftBackItem(VisEquipment __instance, ref string name, ref int variant)
		{
			if (IsHidden)
			{
				VanityManager.OverrideItem(__instance, (VisSlot)0, ref name, ref variant);
			}
			VanityManager.OverrideItem(__instance, (VisSlot)2, ref name, ref variant);
		}

		[HarmonyPatch("SetChestItem")]
		[HarmonyPrefix]
		private static void SetChestItem(VisEquipment __instance, ref string name)
		{
			VanityManager.OverrideItem(__instance, (VisSlot)4, ref name);
		}

		[HarmonyPatch("SetLegItem")]
		[HarmonyPrefix]
		private static void SetLegItem(VisEquipment __instance, ref string name)
		{
			VanityManager.OverrideItem(__instance, (VisSlot)5, ref name);
		}

		[HarmonyPatch("SetHelmetItem")]
		[HarmonyPrefix]
		private static void SetHelmetItem(VisEquipment __instance, ref string name)
		{
			VanityManager.OverrideItem(__instance, (VisSlot)6, ref name);
		}

		[HarmonyPatch("SetShoulderItem")]
		[HarmonyPrefix]
		private static void SetShoulderItem(VisEquipment __instance, ref string name, ref int variant)
		{
			VanityManager.OverrideItem(__instance, (VisSlot)7, ref name, ref variant);
		}

		[HarmonyPatch("SetUtilityItem")]
		[HarmonyPrefix]
		private static void SetUtilityItem(VisEquipment __instance, ref string name)
		{
			VanityManager.OverrideItem(__instance, (VisSlot)8, ref name);
		}

		[HarmonyPatch("SetBeardItem")]
		[HarmonyPrefix]
		private static void SetBeardItem(VisEquipment __instance, ref string name)
		{
			VanityManager.OverrideItem(__instance, (VisSlot)9, ref name);
		}

		[HarmonyPatch("SetHairItem")]
		[HarmonyPrefix]
		private static void SetHairItem(VisEquipment __instance, ref string name)
		{
			VanityManager.OverrideItem(__instance, (VisSlot)10, ref name);
		}

		[HarmonyPatch("SetSkinColor")]
		[HarmonyPrefix]
		private static void SetSkinColor(VisEquipment __instance, ref Vector3 color)
		{
			VanityManager.OverrideSkinColor(__instance, ref color);
		}

		[HarmonyPatch("SetHairColor")]
		[HarmonyPrefix]
		private static void SetHairColor(VisEquipment __instance, ref Vector3 color)
		{
			VanityManager.OverrideHairColor(__instance, ref color);
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int)
	})]
	public class Tooltip
	{
		private static string Postfix(string result, ItemData item, bool crafting)
		{
			if (item == null)
			{
				return result;
			}
			if (crafting)
			{
				return result;
			}
			string name = "";
			int variant = 0;
			VanityManager.OverrideItem(item, ref name, ref variant);
			if (variant != 0)
			{
				name = name + " " + variant;
			}
			if (name != "")
			{
				return result + "\nStyle: <color=orange>" + name + "</color>";
			}
			return result;
		}
	}
	[BepInPlugin("vanity", "Vanity", "1.16")]
	public class Vanity : BaseUnityPlugin
	{
		public const string GUID = "vanity";

		public const string NAME = "Vanity";

		public const string VERSION = "1.16";

		public static ManualLogSource Log;

		public static CustomSyncedValue<string> VanityValue;

		public static ConfigSync ConfigSync = new ConfigSync("vanity")
		{
			DisplayName = "Vanity",
			CurrentVersion = "1.16",
			MinimumRequiredVersion = "1.16",
			IsLocked = true
		};

		private float timer;

		public void Awake()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			VanityValue = new CustomSyncedValue<string>(ConfigSync, "vanity_data");
			VanityValue.ValueChanged += delegate
			{
				VanityData.FromValue(VanityValue.Value);
			};
			new Harmony("vanity").PatchAll();
			VanityData.CreateFile();
			VanityData.SetupWatcher();
			VanityData.FromFile();
		}

		public void Start()
		{
			CommandWrapper.Init();
		}

		public void LateUpdate()
		{
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer())
			{
				timer -= Time.deltaTime;
				if (timer <= 0f)
				{
					timer = 10f;
					VanityData.UpdatePlayerIds();
				}
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	public class SetCommands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<int, List<string>> <>9__0_0;

			public static ConsoleEvent <>9__0_1;

			public static ConsoleOptionsFetcher <>9__0_2;

			internal List<string> <Postfix>b__0_0(int index)
			{
				if (index == 0)
				{
					return Helper.Players();
				}
				return null;
			}

			internal void <Postfix>b__0_1(ConsoleEventArgs args)
			{
				string text = "";
				text = ((args.Length <= 1) ? Helper.GetPlayerID() : Helper.GetPlayerID(string.Join(" ", args.Args.Skip(1))));
				args.Context.AddString(text.ToString());
				GUIUtility.systemCopyBuffer = text.ToString();
			}

			internal List<string> <Postfix>b__0_2()
			{
				return Helper.Players();
			}
		}

		private static void Postfix()
		{
			//IL_004c: 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)
			//IL_0057: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			ChangeEquipment.AddChangeEquipment();
			CommandWrapper.Register("playerid", (int index) => (index == 0) ? Helper.Players() : null);
			object obj = <>c.<>9__0_1;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					string text = "";
					text = ((args.Length <= 1) ? Helper.GetPlayerID() : Helper.GetPlayerID(string.Join(" ", args.Args.Skip(1))));
					args.Context.AddString(text.ToString());
					GUIUtility.systemCopyBuffer = text.ToString();
				};
				<>c.<>9__0_1 = val;
				obj = (object)val;
			}
			object obj2 = <>c.<>9__0_2;
			if (obj2 == null)
			{
				ConsoleOptionsFetcher val2 = () => Helper.Players();
				<>c.<>9__0_2 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("playerid", "[name] - Copies the player id to the clipboard.", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)obj2, false, false, false);
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	public class DisableServerSync
	{
		private static void Finalizer(ZNet __instance)
		{
			if (!__instance.IsDedicated() && __instance.IsServer())
			{
				Vanity.Log.LogInfo((object)"Self hosting detected, disabling server sync.");
				AccessTools.Field(typeof(ConfigSync), "isServer").SetValue(null, false);
			}
		}
	}
}
namespace ServerSync
{
	[PublicAPI]
	public abstract class OwnConfigEntryBase
	{
		public object? LocalBaseValue;

		public bool SynchronizedConfig = true;

		public abstract ConfigEntryBase BaseConfig { get; }
	}
	[PublicAPI]
	public class SyncedConfigEntry<T> : OwnConfigEntryBase
	{
		public readonly ConfigEntry<T> SourceConfig;

		public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;

		public T Value
		{
			get
			{
				return SourceConfig.Value;
			}
			set
			{
				SourceConfig.Value = value;
			}
		}

		public SyncedConfigEntry(ConfigEntry<T> sourceConfig)
		{
			SourceConfig = sourceConfig;
		}

		public void AssignLocalValue(T value)
		{
			if (LocalBaseValue == null)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	public abstract class CustomSyncedValueBase
	{
		public object? LocalBaseValue;

		public readonly string Identifier;

		public readonly Type Type;

		private object? boxedValue;

		protected bool localIsOwner;

		public readonly int Priority;

		public object? BoxedValue
		{
			get
			{
				return boxedValue;
			}
			set
			{
				boxedValue = value;
				this.ValueChanged?.Invoke();
			}
		}

		public event Action? ValueChanged;

		protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
		{
			Priority = priority;
			Identifier = identifier;
			Type = type;
			configSync.AddCustomValue(this);
			localIsOwner = configSync.IsSourceOfTruth;
			configSync.SourceOfTruthChanged += delegate(bool truth)
			{
				localIsOwner = truth;
			};
		}
	}
	[PublicAPI]
	public sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
			}
		}

		public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
			: base(configSync, identifier, typeof(T), priority)
		{
			Value = value;
		}

		public void AssignLocalValue(T value)
		{
			if (localIsOwner)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ConfigurationManagerAttributes
	{
		[UsedImplicitly]
		public bool? ReadOnly = false;
	}
	[PublicAPI]
	public class ConfigSync
	{
		[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
		private static class SnatchCurrentlyHandlingRPC
		{
			public static ZRpc? currentRpc;

			[HarmonyPrefix]
			private static void Prefix(ZRpc __instance)
			{
				currentRpc = __instance;
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		internal static class RegisterRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance)
			{
				isServer = __instance.IsServer();
				foreach (ConfigSync configSync2 in configSyncs)
				{
					ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
					if (isServer)
					{
						configSync2.InitialSyncDone = true;
						Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections"));
					}
				}
				if (isServer)
				{
					((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
				}
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
					{
						new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = isAdmin
						}
					});
					ConfigSync configSync = configSyncs.First();
					if (configSync != null)
					{
						((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
					}
				}
				static IEnumerator WatchAdminListChanges()
				{
					MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
					SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
					List<string> CurrentList = new List<string>(adminList.GetList());
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!adminList.GetList().SequenceEqual(CurrentList))
						{
							CurrentList = new List<string>(adminList.GetList());
							List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p)
							{
								string hostName = p.m_rpc.GetSocket().GetHostName();
								return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName }));
							}).ToList();
							List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class RegisterClientRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (__instance.IsServer())
				{
					return;
				}
				foreach (ConfigSync configSync in configSyncs)
				{
					peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
				}
			}
		}

		private class ParsedConfigs
		{
			public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();

			public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private class ResetConfigsOnShutdown
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ProcessingServerUpdate = true;
				foreach (ConfigSync configSync in configSyncs)
				{
					configSync.resetConfigsFromServer();
					configSync.IsSourceOfTruth = true;
					configSync.InitialSyncDone = false;
				}
				ProcessingServerUpdate = false;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private class SendConfigsAfterLogin
		{
			private class BufferingSocket : ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

				public readonly List<ZPackage> Package = new List<ZPackage>();

				public readonly ISocket Original;

				public BufferingSocket(ISocket original)
				{
					Original = original;
				}

				public bool IsConnected()
				{
					return Original.IsConnected();
				}

				public ZPackage Recv()
				{
					return Original.Recv();
				}

				public int GetSendQueueSize()
				{
					return Original.GetSendQueueSize();
				}

				public int GetCurrentSendRate()
				{
					return Original.GetCurrentSendRate();
				}

				public bool IsHost()
				{
					return Original.IsHost();
				}

				public void Dispose()
				{
					Original.Dispose();
				}

				public bool GotNewData()
				{
					return Original.GotNewData();
				}

				public void Close()
				{
					Original.Close();
				}

				public string GetEndPointString()
				{
					return Original.GetEndPointString();
				}

				public void GetAndResetStats(out int totalSent, out int totalRecv)
				{
					Original.GetAndResetStats(ref totalSent, ref totalRecv);
				}

				public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
				{
					Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec);
				}

				public ISocket Accept()
				{
					return Original.Accept();
				}

				public int GetHostPort()
				{
					return Original.GetHostPort();
				}

				public bool Flush()
				{
					return Original.Flush();
				}

				public string GetHostName()
				{
					return Original.GetHostName();
				}

				public void VersionMatch()
				{
					if (finished)
					{
						Original.VersionMatch();
					}
					else
					{
						versionMatchQueued = Package.Count;
					}
				}

				public void Send(ZPackage pkg)
				{
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005d: Expected O, but got Unknown
					int pos = pkg.GetPos();
					pkg.SetPos(0);
					int num = pkg.ReadInt();
					if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished)
					{
						ZPackage val = new ZPackage(pkg.GetArray());
						val.SetPos(pos);
						Package.Add(val);
					}
					else
					{
						pkg.SetPos(pos);
						Original.Send(pkg);
					}
				}
			}

			[HarmonyPriority(800)]
			[HarmonyPrefix]
			private static void Prefix(ref Dictionary<Assembly, BufferingSocket>? __state, ZNet __instance, ZRpc rpc)
			{
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				if (__instance.IsServer())
				{
					BufferingSocket value = new BufferingSocket(rpc.GetSocket());
					AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, value);
					object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
					ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (val != null && (int)ZNet.m_onlineBackend > 0)
					{
						AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, value);
					}
					if (__state == null)
					{
						__state = new Dictionary<Assembly, BufferingSocket>();
					}
					__state[Assembly.GetExecutingAssembly()] = value;
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
			{
				ZRpc rpc2 = rpc;
				ZNet __instance2 = __instance;
				Dictionary<Assembly, BufferingSocket> __state2 = __state;
				ZNetPeer peer;
				if (__instance2.IsServer())
				{
					object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
					peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (peer == null)
					{
						SendBufferedData();
					}
					else
					{
						((MonoBehaviour)__instance2).StartCoroutine(sendAsync());
					}
				}
				void SendBufferedData()
				{
					if (rpc2.GetSocket() is BufferingSocket bufferingSocket)
					{
						AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original);
						object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
						ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null);
						if (val != null)
						{
							AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original);
						}
					}
					BufferingSocket bufferingSocket2 = __state2[Assembly.GetExecutingAssembly()];
					bufferingSocket2.finished = true;
					for (int i = 0; i < bufferingSocket2.Package.Count; i++)
					{
						if (i == bufferingSocket2.versionMatchQueued)
						{
							bufferingSocket2.Original.VersionMatch();
						}
						bufferingSocket2.Original.Send(bufferingSocket2.Package[i]);
					}
					if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued)
					{
						bufferingSocket2.Original.VersionMatch();
					}
				}
				IEnumerator sendAsync()
				{
					foreach (ConfigSync configSync in configSyncs)
					{
						List<PackageEntry> entries = new List<PackageEntry>();
						if (configSync.CurrentVersion != null)
						{
							entries.Add(new PackageEntry
							{
								section = "Internal",
								key = "serverversion",
								type = typeof(string),
								value = configSync.CurrentVersion
							});
						}
						MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						entries.Add(new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2]
							{
								adminList,
								rpc2.GetSocket().GetHostName()
							}))
						});
						ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false);
						yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package));
					}
					SendBufferedData();
				}
			}
		}

		private class PackageEntry
		{
			public string section = null;

			public string key = null;

			public Type type = null;

			public object? value;
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")]
		private static class PreventSavingServerInfo
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, ref string __result)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase))
				{
					return true;
				}
				__result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType);
				return false;
			}
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")]
		private static class PreventConfigRereadChangingValues
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, string value)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null)
				{
					return true;
				}
				try
				{
					ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
				}
				return false;
			}
		}

		private class InvalidDeserializationTypeException : Exception
		{
			public string expected = null;

			public string received = null;

			public string field = "";
		}

		public static bool ProcessingServerUpdate;

		public readonly string Name;

		public string? DisplayName;

		public string? CurrentVersion;

		public string? MinimumRequiredVersion;

		public bool ModRequired = false;

		private bool? forceConfigLocking;

		private bool isSourceOfTruth = true;

		private static readonly HashSet<ConfigSync> configSyncs;

		private readonly HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>();

		private HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>();

		private static bool isServer;

		private static bool lockExempt;

		private OwnConfigEntryBase? lockedConfig = null;

		private const byte PARTIAL_CONFIGS = 1;

		private const byte FRAGMENTED_CONFIG = 2;

		private const byte COMPRESSED_CONFIG = 4;

		private readonly Dictionary<string, SortedDictionary<int, byte[]>> configValueCache = new Dictionary<string, SortedDictionary<int, byte[]>>();

		private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>();

		private static long packageCounter;

		public bool IsLocked
		{
			get
			{
				bool? flag = forceConfigLocking;
				bool num;
				if (!flag.HasValue)
				{
					if (lockedConfig == null)
					{
						goto IL_0052;
					}
					num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0;
				}
				else
				{
					num = flag.GetValueOrDefault();
				}
				if (!num)
				{
					goto IL_0052;
				}
				int result = ((!lockExempt) ? 1 : 0);
				goto IL_0053;
				IL_0053:
				return (byte)result != 0;
				IL_0052:
				result = 0;
				goto IL_0053;
			}
			set
			{
				forceConfigLocking = value;
			}
		}

		public bool IsAdmin => lockExempt || isSourceOfTruth;

		public bool IsSourceOfTruth
		{
			get
			{
				return isSourceOfTruth;
			}
			private set
			{
				if (value != isSourceOfTruth)
				{
					isSourceOfTruth = value;
					this.SourceOfTruthChanged?.Invoke(value);
				}
			}
		}

		public bool InitialSyncDone { get; private set; } = false;


		public event Action<bool>? SourceOfTruthChanged;

		private event Action? lockedConfigChanged;

		static ConfigSync()
		{
			ProcessingServerUpdate = false;
			configSyncs = new HashSet<ConfigSync>();
			lockExempt = false;
			packageCounter = 0L;
			RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle);
		}

		public ConfigSync(string name)
		{
			Name = name;
			configSyncs.Add(this);
			new VersionCheck(this);
		}

		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry)
		{
			ConfigEntry<T> configEntry2 = configEntry;
			OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry2);
			SyncedConfigEntry<T> syncedEntry = ownConfigEntryBase as SyncedConfigEntry<T>;
			if (syncedEntry == null)
			{
				syncedEntry = new SyncedConfigEntry<T>(configEntry2);
				AccessTools.DeclaredField(typeof(ConfigDescription), "<Tags>k__BackingField").SetValue(((ConfigEntryBase)configEntry2).Description, new object[1]
				{
					new ConfigurationManagerAttributes()
				}.Concat(((ConfigEntryBase)configEntry2).Description.Tags ?? Array.Empty<object>()).Concat(new SyncedConfigEntry<T>[1] { syncedEntry }).ToArray());
				configEntry2.SettingChanged += delegate
				{
					if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig)
					{
						Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry2);
					}
				};
				allConfigs.Add(syncedEntry);
			}
			return syncedEntry;
		}

		public SyncedConfigEntry<T> AddLockingConfigEntry<T>(ConfigEntry<T> lockingConfig) where T : IConvertible
		{
			if (lockedConfig != null)
			{
				throw new Exception("Cannot initialize locking ConfigEntry twice");
			}
			lockedConfig = AddConfigEntry<T>(lockingConfig);
			lockingConfig.SettingChanged += delegate
			{
				this.lockedConfigChanged?.Invoke();
			};
			return (SyncedConfigEntry<T>)lockedConfig;
		}

		internal void AddCustomValue(CustomSyncedValueBase customValue)
		{
			CustomSyncedValueBase customValue2 = customValue;
			if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue2.Identifier))
			{
				throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)");
			}
			allCustomValues.Add(customValue2);
			allCustomValues = new HashSet<CustomSyncedValueBase>(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority));
			customValue2.ValueChanged += delegate
			{
				if (!ProcessingServerUpdate)
				{
					Broadcast(ZRoutedRpc.Everybody, customValue2);
				}
			};
		}

		private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package)
		{
			lockedConfigChanged += serverLockedSettingChanged;
			IsSourceOfTruth = false;
			if (HandleConfigSyncRPC(0L, package, clientUpdate: false))
			{
				InitialSyncDone = true;
			}
		}

		private void RPC_FromOtherClientConfigSync(long sender, ZPackage package)
		{
			HandleConfigSyncRPC(sender, package, clientUpdate: true);
		}

		private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Expected O, but got Unknown
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			try
			{
				if (isServer && IsLocked)
				{
					ZRpc? currentRpc = SnatchCurrentlyHandlingRPC.currentRpc;
					object obj;
					if (currentRpc == null)
					{
						obj = null;
					}
					else
					{
						ISocket socket = currentRpc.GetSocket();
						obj = ((socket != null) ? socket.GetHostName() : null);
					}
					string text = (string)obj;
					if (text != null)
					{
						MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text }))))
						{
							return false;
						}
					}
				}
				cacheExpirations.RemoveAll(delegate(KeyValuePair<long, string> kv)
				{
					if (kv.Key < DateTimeOffset.Now.Ticks)
					{
						configValueCache.Remove(kv.Value);
						return true;
					}
					return false;
				});
				byte b = package.ReadByte();
				if ((b & 2u) != 0)
				{
					long num = package.ReadLong();
					string text2 = sender.ToString() + num;
					if (!configValueCache.TryGetValue(text2, out SortedDictionary<int, byte[]> value))
					{
						value = new SortedDictionary<int, byte[]>();
						configValueCache[text2] = value;
						cacheExpirations.Add(new KeyValuePair<long, string>(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2));
					}
					int key = package.ReadInt();
					int num2 = package.ReadInt();
					value.Add(key, package.ReadByteArray());
					if (value.Count < num2)
					{
						return false;
					}
					configValueCache.Remove(text2);
					package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray());
					b = package.ReadByte();
				}
				ProcessingServerUpdate = true;
				if ((b & 4u) != 0)
				{
					byte[] buffer = package.ReadByteArray();
					MemoryStream stream = new MemoryStream(buffer);
					MemoryStream memoryStream = new MemoryStream();
					using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress))
					{
						deflateStream.CopyTo(memoryStream);
					}
					package = new ZPackage(memoryStream.ToArray());
					b = package.ReadByte();
				}
				if ((b & 1) == 0)
				{
					resetConfigsFromServer();
				}
				ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package);
				ConfigFile val2 = null;
				bool saveOnConfigSet = false;
				foreach (KeyValuePair<OwnConfigEntryBase, object> configValue in parsedConfigs.configValues)
				{
					if (!isServer && configValue.Key.LocalBaseValue == null)
					{
						configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue;
					}
					if (val2 == null)
					{
						val2 = configValue.Key.BaseConfig.ConfigFile;
						saveOnConfigSet = val2.SaveOnConfigSet;
						val2.SaveOnConfigSet = false;
					}
					configValue.Key.BaseConfig.BoxedValue = configValue.Value;
				}
				if (val2 != null)
				{
					val2.SaveOnConfigSet = saveOnConfigSet;
				}
				foreach (KeyValuePair<CustomSyncedValueBase, object> customValue in parsedConfigs.customValues)
				{
					if (!isServer)
					{
						CustomSyncedValueBase key2 = customValue.Key;
						if (key2.LocalBaseValue == null)
						{
							key2.LocalBaseValue = customValue.Key.BoxedValue;
						}
					}
					customValue.Key.BoxedValue = customValue.Value;
				}
				Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name));
				if (!isServer)
				{
					serverLockedSettingChanged();
				}
				return true;
			}
			finally
			{
				ProcessingServerUpdate = false;
			}
		}

		private ParsedConfigs ReadConfigsFromPackage(ZPackage package)
		{
			ParsedConfigs parsedConfigs = new ParsedConfigs();
			Dictionary<string, OwnConfigEntryBase> dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c);
			Dictionary<string, CustomSyncedValueBase> dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c);
			int num = package.ReadInt();
			for (in