Decompiled source of FFSPeak v0.9.1

plugins/com.github.flonou.FFSPeak.dll

Decompiled 3 days ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FFSPeak;
using FFSPeak.CameraSystem;
using FFSPeak.Items;
using FFSPeak.Network;
using FFSPeak.Patches;
using FFSPeak.PlayerState;
using FFSPeak.PlayerState.Mobs;
using FFSPeak.Protocol.Protobuf;
using FFSPeak.RemotePlayers;
using FFSPeak.RemotePlayers.Mobs;
using FFSPeak.UI;
using FFSPeak.UI.AdminCommand;
using FFSPeak.UI.AdminCommand.Buttons;
using FFSPeak.UI.AdminConsole;
using FFSPeak.UI.AdminMessage;
using FFSPeak.UI.EventFeed;
using FFSPeak.UI.Toolbox;
using FFSPeak.Utils;
using Google.Protobuf;
using Google.Protobuf.Collections;
using Google.Protobuf.Reflection;
using HarmonyLib;
using ItemSpawnSync;
using ItemSpawnSync.Data;
using ItemSpawnSync.Patches;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using PEAKLib.UI;
using PEAKLib.UI.Elements;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice.PUN;
using Photon.Voice.Unity;
using TMPro;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.UIElements;
using Zorro.Core;
using Zorro.Settings;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.flonou.FFSPeak")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.9.1.0")]
[assembly: AssemblyInformationalVersion("0.9.1+6438b3476f6a99e558599112683b6378c6297ecf")]
[assembly: AssemblyProduct("com.github.flonou.FFSPeak")]
[assembly: AssemblyTitle("FFSPeak")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.9.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
public class DisableItems
{
	public static void Disable(List<string> itemsToDisable)
	{
		if (itemsToDisable.Count == 0)
		{
			Plugin.Logger.LogMessage((object)"No GameObjects configured to be disabled.");
			return;
		}
		int num = 0;
		foreach (string item in itemsToDisable)
		{
			Item[] array = FindItemsByName(item);
			Item[] array2 = array;
			foreach (Item val in array2)
			{
				((Component)val).gameObject.SetActive(false);
				num++;
				Plugin.Logger.LogInfo((object)("Disabled GameObject: " + ((Object)val).name));
			}
		}
		Plugin.Logger.LogMessage((object)$"Successfully disabled {num} GameObject(s).");
	}

	public static void DisableBackpacksPhysics()
	{
		Item[] array = (Item[])(object)Object.FindObjectsByType<Backpack>((FindObjectsInactive)1, (FindObjectsSortMode)0);
		Item[] array2 = array;
		if (Plugin.IsObserver)
		{
			for (int i = 1; i < array2.Length; i++)
			{
				array2[0].rig.detectCollisions = false;
				array2[0].rig.isKinematic = true;
			}
		}
	}

	public static Item[] FindItemsByName(string name)
	{
		return (from obj in Resources.FindObjectsOfTypeAll<Item>()
			where ((Object)obj).name == name
			select obj).ToArray();
	}

	public static void RunDisableLogic()
	{
		Plugin.Logger.LogMessage((object)"Running DisableItems logic");
		Disable(new List<string> { "Guidebook(Clone)", "Frisbee(Clone)", "BingBong(Clone)", "Shell Big(Clone)", "Flare(Clone)", "Bugle(Clone)", "Compass(Clone)", "GuidebookPageScroll(Clone)", "GuidebookPageScroll Variant(Clone)", "Binoculars(Clone)" });
		DisableBackpacksPhysics();
		Object.FindObjectsByType<TornadoSpawner>((FindObjectsInactive)1, (FindObjectsSortMode)0).ToList().ForEach(delegate(TornadoSpawner val)
		{
			((Component)val).gameObject.SetActive(false);
		});
		List<string> source = new List<string> { "Dynamite" };
		PropSpawner[] array = Object.FindObjectsByType<PropSpawner>((FindObjectsInactive)1, (FindObjectsSortMode)0);
		foreach (PropSpawner spawner in array)
		{
			if (source.Any((string name) => ((Object)spawner).name.StartsWith(name)))
			{
				((Component)spawner).gameObject.SetActive(false);
				Plugin.Logger.LogInfo((object)("Disabled GameObject: " + ((Object)spawner).name));
			}
		}
		_ = Plugin.IsObserver;
	}

	public static void DisableLavaRiversOutsideCaldera()
	{
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Expected O, but got Unknown
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Expected O, but got Unknown
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		Biome[] array = Object.FindObjectsByType<Biome>((FindObjectsInactive)0, (FindObjectsSortMode)0);
		foreach (Biome val in array)
		{
			if (!((Object)val).name.StartsWith("Volcano"))
			{
				continue;
			}
			for (int j = 0; j < ((Component)val).transform.childCount; j++)
			{
				Transform child = ((Component)val).transform.GetChild(j);
				if (!((Object)child).name.StartsWith("Caldera"))
				{
					continue;
				}
				foreach (Transform item in child)
				{
					Transform val2 = item;
					if (!((Object)val2).name.StartsWith("LavaRivers"))
					{
						continue;
					}
					foreach (Transform item2 in val2)
					{
						Transform val3 = item2;
						if (((Component)val3).transform.position.z > 1850f || ((Component)val3).transform.position.y > 1150f)
						{
							((Component)val3).gameObject.SetActive(false);
							Plugin.Logger.LogMessage((object)("Disabled GameObject: " + ((Object)val3).name + " in biome " + ((Object)val).name));
						}
					}
					Plugin.Logger.LogMessage((object)("Disabled GameObject: " + ((Object)val2).name + " in biome " + ((Object)val).name));
				}
			}
		}
	}
}
[Serializable]
public class ResumeDTO : BaseDTO
{
	public new string LobbyCode;

	public FFSPeak.Network.PlayerStateDTO PlayerState;

	public PlayerCustomizationDTO Customization;

	public JToken Items;

	public ResumeDTO(string playerName, string lobbyCode, FFSPeak.Network.PlayerStateDTO playerState, PlayerCustomizationDTO customization, JToken items)
	{
		PlayerName = playerName;
		LobbyCode = lobbyCode;
		PlayerState = playerState;
		Customization = customization;
		Items = items;
	}
}
[DefaultExecutionOrder(99999)]
public class RemotePlayerRope : MonoBehaviour
{
	private RopeBoneVisualizer ropeBoneVisualizer;

	private RopeSyncDTO ropeSyncLast;

	public Rope Rope { get; set; }

	public void HandleRopeSync(RopeSyncDTO ropeSync)
	{
		ropeSyncLast = ropeSync;
		UpdateRopeFromSync();
	}

	public void Initialize(Rope ropeComponent, RopeAnchor ropeAnchor, int segmentCount)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		Rope = ropeComponent;
		Rope.creatorLeft = false;
		Rope.Segments = segmentCount;
		Rope.attachmenState = (ATTACHMENT)2;
		ropeBoneVisualizer = ((Component)this).GetComponentInChildren<RopeBoneVisualizer>();
		ropeBoneVisualizer.StartTransform = ((Component)ropeAnchor.anchorPoint).transform;
		RemotePlayer.ViewIsMineProperty.SetValue(((MonoBehaviourPun)Rope).photonView, false);
	}

	public void UpdateRopeFromSync()
	{
		//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_002a: Unknown result type (might be due to invalid IL or missing references)
		if (ropeSyncLast == null)
		{
			Plugin.Logger.LogWarning((object)"UpdateRopeFromSync: ropeSyncLast is null");
			return;
		}
		RopeSyncData syncData = ropeSyncLast.ToRopeSyncData();
		Rope.SetSyncData(syncData);
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace FFSPeak
{
	public class CampfireManager : Singleton<CampfireManager>
	{
		private List<Campfire> campfireComponents = new List<Campfire>();

		private List<Transform> campfires = new List<Transform>();

		private string lastSentCheckpointHash;

		private GameObject newCampfire;

		public int GetCampfireIndex(Campfire campfire)
		{
			//IL_0019: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0062: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			int num = campfireComponents.IndexOf(campfire);
			if (num >= 0)
			{
				return num;
			}
			Vector3 position = ((Component)campfire).transform.position;
			float num2 = float.MaxValue;
			int result = -1;
			for (int i = 0; i < campfires.Count; i++)
			{
				if (!((Object)(object)campfires[i] == (Object)null))
				{
					Vector3 val = campfires[i].position - position;
					float num3 = val.y * val.y + val.z * val.z;
					if (num3 < num2)
					{
						num2 = num3;
						result = i;
					}
				}
			}
			if (num2 < 5f)
			{
				return result;
			}
			Plugin.Logger.LogWarning((object)("GetCampfireIndex: '" + ((Object)campfire).name + "' not found and no nearby campfire within threshold. Returning -1."));
			return -1;
		}

		public IEnumerable<Transform> GetCampfires()
		{
			if (campfires.Count == 0 && (Object)(object)Singleton<MapHandler>.Instance != (Object)null)
			{
				UpdateCampfires();
			}
			return campfires;
		}

		public void UpdateCampfires()
		{
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			campfires.Clear();
			campfireComponents.Clear();
			MapHandler val = Singleton<MapHandler>.Instance;
			foreach (MapSegment item in val.segments.Where((MapSegment s) => (Object)(object)s.segmentCampfire != (Object)null))
			{
				Campfire componentInChildren = item.segmentCampfire.GetComponentInChildren<Campfire>();
				campfires.Add(((Component)componentInChildren).transform);
				campfireComponents.Add(componentInChildren);
			}
			Campfire val2 = campfireComponents[0];
			campfires.Insert(0, ((Component)SpawnPoint.allSpawnPoints[0]).transform);
			campfireComponents.Insert(0, null);
			GameObject val3 = GameObject.Find("Flag_planted_seagull");
			if ((Object)(object)val3 != (Object)null)
			{
				if ((Object)(object)newCampfire == (Object)null)
				{
					newCampfire = PhotonCloneUtils.CloneWithPhoton(((Component)val2).gameObject, val3.transform);
					if ((Object)(object)newCampfire == (Object)null)
					{
						Plugin.Logger.LogWarning((object)"Failed to clone campfire with Photon");
						return;
					}
					newCampfire.transform.localPosition = Vector3.zero;
					newCampfire.transform.localRotation = Quaternion.identity;
				}
				Campfire componentInChildren2 = newCampfire.GetComponentInChildren<Campfire>();
				campfires.Add(((Component)componentInChildren2).transform);
				campfireComponents.Add(componentInChildren2);
			}
			else
			{
				campfires.Add(Singleton<MountainProgressHandler>.Instance.progressPoints.Last().transform);
				campfireComponents.Add(null);
			}
			Plugin.Logger.LogInfo((object)string.Format("Updated campfires: {0}. Total campfires: {1}", string.Join(", ", campfires.Select((Transform c) => ((Object)c).name)), campfires.Count));
			SendCheckpointPositionsIfChanged();
		}

		private void SendCheckpointPositionsIfChanged()
		{
			try
			{
				CheckpointPositionsDTO.CheckpointEntry[] array = campfires.Select((Transform t, int i) => new CheckpointPositionsDTO.CheckpointEntry
				{
					Index = i,
					Position = (((Object)(object)t != (Object)null) ? t.position : Vector3.zero)
				}).ToArray();
				string text = string.Join("|", array.Select((CheckpointPositionsDTO.CheckpointEntry e) => $"{Mathf.RoundToInt(e.Position.x)},{Mathf.RoundToInt(e.Position.y)},{Mathf.RoundToInt(e.Position.z)}")).GetHashCode().ToString("X8");
				if (!(text == lastSentCheckpointHash))
				{
					lastSentCheckpointHash = text;
					CheckpointPositionsDTO dto = new CheckpointPositionsDTO
					{
						Checkpoints = array,
						Hash = text
					};
					if (Plugin.IsPlayer)
					{
						PlayerNetworkManager.SendCheckpointPositions(dto);
					}
					if (Plugin.IsObserver)
					{
						NetworkManager.ObserverNetworkManager?.SendCheckpointPositions(dto);
					}
					Plugin.Logger.LogMessage((object)$"Sent {array.Length} checkpoint positions to server (hash: {text})");
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Failed to send checkpoint positions: " + ex.Message));
			}
		}
	}
	public class InputManager : Singleton<InputManager>
	{
		public static bool IsFrozen = false;

		public static bool InputsEnabled = true;

		public static bool PlayersInputsEnabled = true;

		public static bool ShouldBeInvincible;

		protected bool willFreeze;

		protected Dictionary<BodypartType, Vector3> originalBodypartPositions = new Dictionary<BodypartType, Vector3>();

		public void Freeze()
		{
			IsFrozen = true;
			originalBodypartPositions.Clear();
			willFreeze = true;
			DisableInputs();
		}

		public void Unfreeze()
		{
			IsFrozen = false;
			willFreeze = false;
			originalBodypartPositions.Clear();
			if ((Object)(object)Character.localCharacter != (Object)null && (Object)(object)Character.localCharacter.refs.ragdoll != (Object)null && Character.localCharacter.refs.ragdoll.rigidbodies != null)
			{
				Character.localCharacter.refs.ragdoll.ToggleKinematic(false);
			}
			EnableInputs();
		}

		public void DisableInputs()
		{
			InputsEnabled = false;
			PlayersInputsEnabled = false;
			if (Plugin.IsPlayer)
			{
				ShouldBeInvincible = true;
				((MonoBehaviour)this).StartCoroutine(EnableInvincibility());
			}
			Singleton<InputDisabledUI>.Instance.Show();
			Plugin.Logger.LogMessage((object)"Inputs Disabled");
		}

		public void DisableInputsTemporarily(float duration)
		{
			DisableInputs();
			((MonoBehaviour)this).Invoke("EnableInputs", duration);
		}

		public void ToggleInvincibility(bool enabled)
		{
			if (Plugin.IsPlayer)
			{
				if (enabled)
				{
					ShouldBeInvincible = true;
					((MonoBehaviour)this).StartCoroutine(EnableInvincibility());
				}
				else
				{
					ShouldBeInvincible = false;
					((MonoBehaviour)this).StopCoroutine(EnableInvincibility());
				}
			}
		}

		public void EnableInputs()
		{
			InputsEnabled = true;
			PlayersInputsEnabled = true;
			ShouldBeInvincible = false;
			((MonoBehaviour)this).StopCoroutine(EnableInvincibility());
			Singleton<InputDisabledUI>.Instance.Hide();
			Plugin.Logger.LogMessage((object)"Inputs Enabled");
		}

		public static void FreezePlayers()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Singleton<EventFeedUIManager>.Instance?.ShowMessage(new SimpleEventMessage("Freezing players!", Color.red, 2f));
			NetworkManager.ObserverNetworkManager?.SendAdminCommand("broadcast_message", new BroadcastMessageDTO
			{
				Message = "Freezing players!",
				Color = "#FF0000",
				Lifetime = 2f
			});
			Plugin.Logger.LogMessage((object)"Sending freeze command");
			int value = Singleton<AdminCommandUIManager>.Instance.LoadedLevelIndex.Value;
			NetworkManager.ObserverNetworkManager?.SendAdminCommand("load_level", new LoadLevelDTO
			{
				LevelIndex = value,
				Freeze = true
			});
			Singleton<AdminCommandUIManager>.Instance.PlayersFrozen = true;
		}

		public void SetAfflictions()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			if (ShouldBeInvincible && FFSPeak.PlayerState.PlayerState.IsInitialized)
			{
				Affliction val = default(Affliction);
				if (!Character.localCharacter.refs.afflictions.HasAfflictionType((AfflictionType)16, ref val))
				{
					Character.localCharacter.refs.afflictions.AddAffliction((Affliction)new Affliction_Invincibility
					{
						totalTime = 0.5f
					}, false);
				}
				if (!Character.localCharacter.refs.afflictions.HasAfflictionType((AfflictionType)21, ref val))
				{
					Character.localCharacter.refs.afflictions.AddAffliction((Affliction)new Affliction_NoHunger
					{
						totalTime = 0.5f
					}, false);
				}
			}
		}

		public static IEnumerator UnfreezeCountdown()
		{
			for (int i = 5; i >= 1; i--)
			{
				string message = $"Unfreezing in {i}...";
				Singleton<EventFeedUIManager>.Instance?.ShowMessage(new SimpleEventMessage(message, Color.yellow, 1f));
				NetworkManager.ObserverNetworkManager?.SendAdminCommand("broadcast_message", new BroadcastMessageDTO
				{
					Message = message,
					Color = "#FFFF00",
					Lifetime = 1f
				});
				Plugin.Logger.LogMessage((object)$"Countdown: {i}");
				yield return (object)new WaitForSeconds(1f);
			}
			Singleton<EventFeedUIManager>.Instance?.ShowMessage(new SimpleEventMessage("Unfreezing players!", Color.green, 2f));
			NetworkManager.ObserverNetworkManager?.SendAdminCommand("broadcast_message", new BroadcastMessageDTO
			{
				Message = "Unfreezing players!",
				Color = "#00FF00",
				Lifetime = 2f
			});
			Plugin.Logger.LogMessage((object)"Sending unfreeze command");
			int value = Singleton<AdminCommandUIManager>.Instance.LoadedLevelIndex.Value;
			NetworkManager.ObserverNetworkManager?.SendAdminCommand("load_level", new LoadLevelDTO
			{
				LevelIndex = value,
				Freeze = false
			});
			Singleton<AdminCommandUIManager>.Instance.PlayersFrozen = false;
		}

		public void Update()
		{
			if (Plugin.IsPlayer && ShouldBeInvincible)
			{
				SetAfflictions();
			}
		}

		public void FixedUpdate()
		{
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.IsPlayer || !Plugin.IsOnMapScene || !IsFrozen || !(Time.timeSinceLevelLoad > 15f))
			{
				return;
			}
			if (willFreeze)
			{
				Plugin.Logger.LogMessage((object)"Freezing player character");
				if (!((Object)(object)Character.localCharacter != (Object)null) || !((Object)(object)Character.localCharacter.refs.ragdoll != (Object)null) || Character.localCharacter.refs.ragdoll.rigidbodies == null)
				{
					return;
				}
				Character.localCharacter.refs.ragdoll.ToggleKinematic(true);
				foreach (Bodypart part in Character.localCharacter.refs.ragdoll.partList)
				{
					if (!originalBodypartPositions.ContainsKey(part.partType))
					{
						originalBodypartPositions[part.partType] = ((Component)part.rig).transform.position;
					}
				}
				willFreeze = false;
				return;
			}
			Character.localCharacter.refs.ragdoll.ToggleKinematic(true);
			foreach (Bodypart part2 in Character.localCharacter.refs.ragdoll.partList)
			{
				if (originalBodypartPositions.TryGetValue(part2.partType, out var value) && value != Vector3.zero)
				{
					((Component)part2.rig).transform.position = value;
				}
			}
		}

		protected override void Initialize()
		{
			Plugin.Logger.LogMessage((object)"InputManager initialized");
		}

		private IEnumerator EnableInvincibility()
		{
			ShouldBeInvincible = true;
			yield return (object)new WaitUntil((Func<bool>)(() => FFSPeak.PlayerState.PlayerState.IsInitialized));
			SetAfflictions();
			Plugin.Logger.LogMessage((object)"Invincibility Enabled");
		}
	}
	[BepInProcess("PEAK.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.github.flonou.FFSPeak", "FFSPeak", "0.9.1")]
	public class Plugin : BaseUnityPlugin
	{
		private ConfigEntry<bool> autoLoadItems;

		private ConfigEntry<bool> autoOpenLuggages;

		private readonly Harmony harmony = new Harmony("com.zerator.ffspeak");

		private ConfigEntry<bool> isObserver;

		private ConfigEntry<bool> isPlayer;

		private ConfigEntry<bool> loadFromFile;

		private ConfigEntry<bool> saveSpawnDataToLocalFile;

		private ConfigEntry<string> lobbyCode;

		private string observerKey;

		private ConfigEntry<string> observerKeyFile;

		private ConfigEntry<string> serverUrl;

		private ConfigEntry<bool> autoOpenAdminConsole;

		private ConfigEntry<KeyboardShortcut> adminConsoleShortcut;

		private ConfigEntry<bool> scoreLoggingEnabled;

		private ConfigEntry<string> scoreLoggingFolderPath;

		private ConfigEntry<float> scoreLoggingInterval;

		public const string Id = "com.github.flonou.FFSPeak";

		public static bool AutoOpenLuggages => Instance.autoOpenLuggages.Value;

		public static AssetBundle FfsPeakAssets { get; private set; }

		public static Plugin Instance { get; private set; }

		public static bool IsInLobby { get; private set; } = false;

		public static bool IsObserver => Instance.isObserver.Value;

		public static bool IsOnMapScene { get; private set; } = false;

		public static bool IsPlayer => Instance.isPlayer.Value;

		public static int? LevelToLoad { get; set; } = null;

		public static bool LoadingLevel { get; set; } = false;

		public static string LobbyCode { get; set; } = "000000";

		public static int? LobbyPlayerLimit { get; set; } = null;

		public static bool ShouldLoadItems
		{
			get
			{
				if (Instance.autoLoadItems.Value)
				{
					return LoadItemsOnNextMapLoad;
				}
				return false;
			}
		}

		public static bool LoadItemsOnNextMapLoad { get; set; } = true;

		public static bool ScoreLoggingEnabled => Instance.scoreLoggingEnabled.Value;

		public static string ScoreLoggingFolderPath => Instance.scoreLoggingFolderPath.Value;

		public static float ScoreLoggingInterval => Instance.scoreLoggingInterval.Value;

		public static string LocalPlayerName { get; private set; } = "UnknownPlayer" + Guid.NewGuid().ToString().Substring(0, 10);

		public static ManualLogSource Logger { get; set; }

		public static bool MapSceneReady { get; set; } = false;

		public static string SceneName { get; private set; } = null;

		public static bool AutoOpenAdminConsole => Instance.autoOpenAdminConsole.Value;

		public string ServerUrl => serverUrl.Value;

		public static string Name => "FFSPeak";

		public static string Version => "0.9.1";

		public static event Action<string> LevelLoaded;

		private static string TryGetArgValue(string[] args, params string[] names)
		{
			if (args == null || args.Length == 0 || names == null || names.Length == 0)
			{
				return null;
			}
			for (int i = 0; i < args.Length; i++)
			{
				string text = args[i];
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				foreach (string text2 in names)
				{
					if (!string.IsNullOrEmpty(text2))
					{
						if (string.Equals(text, text2, StringComparison.OrdinalIgnoreCase) && i + 1 < args.Length)
						{
							return args[i + 1];
						}
						string text3 = text2 + "=";
						if (text.StartsWith(text3, StringComparison.OrdinalIgnoreCase))
						{
							return text.Substring(text3.Length);
						}
					}
				}
			}
			return null;
		}

		public static string GetMapName()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (SceneName != null)
			{
				return SceneName;
			}
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene sceneAt = SceneManager.GetSceneAt(i);
				if (((Scene)(ref sceneAt)).name.Contains("Level_"))
				{
					SceneName = ((Scene)(ref sceneAt)).name;
					return ((Scene)(ref sceneAt)).name;
				}
			}
			return null;
		}

		public static void HandleLoadLevel(int levelIndex = -1, int? playerLimit = 50)
		{
			Logger.LogMessage((object)$"Received load level command from server: levelIndex={levelIndex}, playerLimit={playerLimit}");
			LevelToLoad = levelIndex;
			LobbyPlayerLimit = playerLimit;
			if (levelIndex < 0)
			{
				Logger.LogMessage((object)"Level load cleared by server");
				LevelToLoad = null;
			}
			else if (IsInLobby && !LoadingLevel)
			{
				LoadingLevel = true;
				((MonoBehaviour)Instance).StartCoroutine(AutoStartGameInAirport(levelIndex));
				if (IsObserver)
				{
					Singleton<AdminCommandUIManager>.Instance.LoadedLevelIndex = levelIndex;
				}
			}
		}

		public static IEnumerator TryCapturePlayerName()
		{
			while (PhotonNetwork.LocalPlayer == null || string.IsNullOrEmpty(PhotonNetwork.LocalPlayer.NickName))
			{
				yield return null;
			}
			try
			{
				LocalPlayerName = PhotonNetwork.LocalPlayer.NickName;
				if (IsObserver && !IsPlayer)
				{
					LocalPlayerName += "_Obs";
				}
				Logger.LogMessage((object)("Captured player name from Photon: " + LocalPlayerName));
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Error capturing player name: " + ex.Message));
			}
		}

		public void Update()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown((KeyCode)289))
			{
				Singleton<FPSUI>.Instance.ToggleShow();
			}
			if (!IsObserver)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)284))
			{
				Singleton<RemotePlayerAdministrationUIManager>.Instance.Toggle();
			}
			if (Input.GetKeyDown((KeyCode)285))
			{
				Singleton<RemoteMessageUIManager>.Instance.Toggle();
			}
			if (Input.GetKeyDown((KeyCode)290))
			{
				Singleton<LobbyManagerUIManager>.Instance.Toggle();
			}
			if (Input.GetKeyDown((KeyCode)291))
			{
				Singleton<AdminCommandUIManager>.Instance.ToggleDisplay();
			}
			if (Input.GetKeyDown((KeyCode)292))
			{
				Singleton<ToolboxUIManager>.Instance.ToggleDisplay();
			}
			KeyboardShortcut value = adminConsoleShortcut.Value;
			if (Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey))
			{
				value = adminConsoleShortcut.Value;
				if (((KeyboardShortcut)(ref value)).Modifiers != null)
				{
					value = adminConsoleShortcut.Value;
					if (!((KeyboardShortcut)(ref value)).Modifiers.All((KeyCode m) => Input.GetKey(m)))
					{
						goto IL_0100;
					}
				}
				Singleton<AdminConsoleUIManager>.Instance.Toggle();
			}
			goto IL_0100;
			IL_0100:
			if (Input.GetKeyDown((KeyCode)115) && Input.GetKey((KeyCode)306))
			{
				scoreLoggingEnabled.Value = !scoreLoggingEnabled.Value;
				if (scoreLoggingEnabled.Value)
				{
					Singleton<ScoreLogger>.Instance.LogScores();
				}
			}
		}

		protected void Awake()
		{
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			isObserver = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IsObserver", false, "Should this instance act as an observer?");
			isPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IsPlayer", true, "Should this instance act as a player?");
			serverUrl = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ServerUrl", "ws://localhost:4000", "The WebSocket server URL to connect to.");
			lobbyCode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "LobbyCode", "000000", "Lobby code (6 chars A-Z0-9) used to isolate instances. Same code = same lobby.");
			autoLoadItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Items", "AutoLoadItems", true, "Should automatically load items when joining a map?");
			loadFromFile = ((BaseUnityPlugin)this).Config.Bind<bool>("Items", "LoadFromFile", true, "Load item data from files");
			saveSpawnDataToLocalFile = ((BaseUnityPlugin)this).Config.Bind<bool>("Items", "SaveSpawnDataToLocalFile", true, "Save spawn data to local file when saving through the shortcut");
			autoOpenLuggages = ((BaseUnityPlugin)this).Config.Bind<bool>("AdminCommands", "AutoOpenLuggages", false, "Automatically open all luggages for observers when a level is loaded (for easier spectating)");
			autoOpenAdminConsole = ((BaseUnityPlugin)this).Config.Bind<bool>("AdminCommands", "AutoOpenAdminConsole", false, "Automatically open the admin console when the game starts");
			adminConsoleShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("AdminCommands", "AdminConsoleShortcut", new KeyboardShortcut((KeyCode)282, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Keyboard shortcut to open the admin console");
			scoreLoggingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("ScoreLogging", "ScoreLoggingEnabled", false, "Enable score logging to a file");
			scoreLoggingFolderPath = ((BaseUnityPlugin)this).Config.Bind<string>("ScoreLogging", "ScoreLoggingFolderPath", "Scores", "File path for score logging (relative to the peak application)");
			scoreLoggingInterval = ((BaseUnityPlugin)this).Config.Bind<float>("ScoreLogging", "ScoreLoggingInterval", 5f, "Interval in seconds for logging scores to the file");
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			if (commandLineArgs.Contains("-observer"))
			{
				isObserver.Value = true;
				isPlayer.Value = false;
			}
			if (commandLineArgs.Contains("-player"))
			{
				isPlayer.Value = true;
				isObserver.Value = false;
			}
			string text = TryGetArgValue(commandLineArgs, "-serverurl", "--server-url", "--serverurl", "-url", "--url");
			if (!string.IsNullOrWhiteSpace(text))
			{
				serverUrl.Value = text.Trim();
				Logger.LogMessage((object)("Overriding server URL from command line: " + serverUrl.Value));
			}
			string text2 = TryGetArgValue(commandLineArgs, "-port", "--port", "-wsport", "--ws-port", "--wsport");
			if (!string.IsNullOrWhiteSpace(text2))
			{
				if (int.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result > 0 && result <= 65535)
				{
					try
					{
						Uri uri = new Uri(serverUrl.Value);
						UriBuilder uriBuilder = new UriBuilder(uri)
						{
							Port = result
						};
						serverUrl.Value = uriBuilder.Uri.ToString().TrimEnd('/');
						Logger.LogMessage((object)$"Overriding server port from command line: {result} -> {serverUrl.Value}");
					}
					catch (Exception ex)
					{
						Logger.LogWarning((object)("Could not apply command line port override '" + text2 + "' to server URL '" + serverUrl.Value + "': " + ex.Message));
					}
				}
				else
				{
					Logger.LogWarning((object)("Ignoring invalid port value from command line: '" + text2 + "'"));
				}
			}
			Logger.LogMessage((object)("Plugin " + Name + " is loaded!"));
			Logger.LogMessage((object)$"Network Mode - Player: {IsPlayer}, Observer: {IsObserver}");
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			ItemActionBase_RunAction_Patch.ApplyPatches(harmony);
			ModChecker.Check();
			((MonoBehaviour)this).StartCoroutine(AutoLoadItems.LoadItemsFromFiles());
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			LobbyCode = lobbyCode.Value;
			observerKeyFile = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ObserverKeyFile", "observer_key.txt", "Filename for the observer key (relative to config/FFSPeak/)");
			if (IsObserver)
			{
				string path = Path.Combine(Paths.ConfigPath, "FFSPeak");
				string text3 = observerKeyFile.Value;
				if (!Path.IsPathRooted(text3))
				{
					text3 = Path.Combine(path, text3);
				}
				if (File.Exists(text3))
				{
					observerKey = File.ReadAllText(text3).Trim();
					Logger.LogMessage((object)("Loaded observer key from " + text3));
				}
				else
				{
					Logger.LogWarning((object)("Observer key file not found: " + text3));
				}
				if (scoreLoggingEnabled.Value)
				{
					Singleton<ScoreLogger>.Instance.LogScores();
				}
			}
			if (IsPlayer)
			{
				ModChecker.StartCheckAsync();
			}
			if (IsObserver)
			{
				SpawnerSpawnItemsPatch.OnItemsSpawned += delegate(List<PhotonView> photonViews)
				{
					foreach (PhotonView photonView in photonViews)
					{
						Item component = ((Component)photonView).GetComponent<Item>();
						if ((Object)(object)component.rig != (Object)null)
						{
							component.rig.isKinematic = true;
							((Behaviour)component).enabled = false;
							Logger.LogInfo((object)("Set item " + ((Object)component).name + " to kinematic for observer and disabled item script."));
						}
					}
				};
			}
			string text4 = Path.Combine(Paths.PluginPath, "FFSPeak", "ffspeak_assets.bundle");
			FfsPeakAssets = AssetBundle.LoadFromFile(text4);
			Logger.LogMessage((object)$"Loaded asset bundle with name [ffspeak_assets.bundle]: success={(Object)(object)FfsPeakAssets != (Object)null}");
			string[] allAssetNames = FfsPeakAssets.GetAllAssetNames();
			Logger.LogMessage((object)("Assets in bundle: " + string.Join(", ", allAssetNames)));
			if (saveSpawnDataToLocalFile.Value)
			{
				Plugin.Instance.OnSpawnDataSaved += delegate(string text6)
				{
					string text5 = Path.GetFileName(text6);
					if (text5.StartsWith("Level_"))
					{
						int num = text5.IndexOf('_', 6);
						if (num > 0)
						{
							text5 = text5.Substring(0, num) + ".json";
						}
					}
					else
					{
						text5 = Path.GetFileNameWithoutExtension(text5) + ".json";
					}
					string text7 = Path.Combine(Paths.ConfigPath, "FFSPeak", text5);
					File.Copy(text6, text7, overwrite: true);
					Logger.LogMessage((object)("Copied spawn data file to " + text7));
					((MonoBehaviour)this).StartCoroutine(AutoLoadItems.LoadItemsFromFiles());
				};
			}
			if ((Object)(object)RemoteMessageHandler.Instance == (Object)null)
			{
				((Component)this).gameObject.AddComponent<RemoteMessageHandler>();
			}
		}

		private static IEnumerator AutoStartGameInAirport(int levelIndex)
		{
			yield return null;
			try
			{
				Logger.LogMessage((object)$"Auto-starting game with level index: {levelIndex} with {LobbyPlayerLimit} player limit");
				while (LoadingScreenHandler.loading)
				{
					yield return null;
				}
				AirportCheckInKiosk kiosk = null;
				while ((Object)(object)kiosk == (Object)null)
				{
					kiosk = Object.FindFirstObjectByType<AirportCheckInKiosk>();
					if ((Object)(object)kiosk == (Object)null)
					{
						yield return null;
					}
				}
				yield return null;
				string level = SingletonAsset<MapBaker>.Instance.GetLevel((levelIndex >= 0) ? levelIndex : Ascents.currentAscent);
				RunSettings.Init();
				byte[] serializedRunSettings = RunSettings.GetSerializedRunSettings();
				Logger.LogMessage((object)("Starting game with level parameter: " + level));
				((MonoBehaviourPun)kiosk).photonView.RPC("BeginIslandLoadRPC", (RpcTarget)0, new object[3] { level, 0, serializedRunSettings });
			}
			finally
			{
				LoadingLevel = false;
			}
		}

		public static void ReturnToAirport()
		{
			Logger.LogMessage((object)"Returning to airport...");
			Player.LeaveCurrentGame();
		}

		private IEnumerator InitializeNetworkManager()
		{
			NetworkConnector connector = null;
			while ((Object)(object)connector == (Object)null)
			{
				connector = Object.FindFirstObjectByType<NetworkConnector>();
				if ((Object)(object)connector == (Object)null || !((Behaviour)connector).enabled)
				{
					connector = null;
					yield return null;
				}
			}
			yield return null;
			_ = Singleton<RemotePlayerManager>.Instance;
			NetworkManager.Initialize(new NetworkConfig
			{
				ServerUrl = ServerUrl,
				LobbyCode = LobbyCode,
				EnableNetworking = true,
				IsPlayer = IsPlayer,
				IsObserver = IsObserver,
				TimeoutMs = 5000,
				ObserverKey = observerKey
			});
			if (IsObserver)
			{
				ObserverNetworkManager.WsClient.WsClient.RegisterServerMessageHandler("lobby_join_result", OnLobbyJoined);
				ObserverNetworkManager.WsClient.WsClient.RegisterServerMessageHandler("message", OnServerMessage);
			}
			if (IsPlayer)
			{
				PlayerNetworkManager.WsClient.WsClient.RegisterServerMessageHandler("lobby_join_result", OnLobbyJoined);
				PlayerNetworkManager.WsClient.WsClient.RegisterServerMessageHandler("message", OnServerMessage);
			}
		}

		private void OnServerMessage(ServerMessageDTO dTO)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			Logger.LogMessage((object)("Received server message: subtype=" + dTO.Subtype + ", data=" + dTO.Data));
			Singleton<EventFeedUIManager>.Instance?.ShowMessage(new SimpleEventMessage("Server: " + dTO.Data, Color.cyan, 5f));
		}

		private bool IsSceneLoaded(string nameContains)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene sceneAt = SceneManager.GetSceneAt(i);
				if (((Scene)(ref sceneAt)).name.Contains(nameContains))
				{
					return true;
				}
			}
			return false;
		}

		private IEnumerator MapSceneLoaded()
		{
			while ((Object)(object)RunManager.Instance == (Object)null || RunManager.Instance.timeSinceRunStarted <= 0f)
			{
				yield return null;
			}
			Singleton<CampfireManager>.Instance.UpdateCampfires();
			Singleton<RemotePlayerManager>.Instance.Clear();
			HeightBarsUIManager.Instance.Reinitialize();
			if (IsObserver)
			{
				Singleton<PlayerListUIManager>.Instance.Clear();
				Singleton<PlayerListUIManager>.Instance.SetDisplay(show: true);
				((Behaviour)Singleton<PlayerListUIManager>.Instance).enabled = true;
				Singleton<LobbyManagerUIManager>.Instance.Hide();
				Singleton<RemotePlayerAdministrationUIManager>.Instance.Hide();
			}
			if (IsPlayer)
			{
				ModChecker.StartCheckAsync();
				Singleton<JoinLobbyUI>.Instance.Hide();
				yield return FFSPeak.PlayerState.PlayerState.AddPlayerStateToCharacter();
				((Component)Character.localCharacter).gameObject.AddComponent<MobStateSender>();
			}
			if (IsPlayer && CheckpointTeleportUI.Enabled)
			{
				_ = Singleton<CheckpointTeleportUI>.Instance;
				Singleton<CheckpointTeleportUI>.Instance.Refresh();
			}
			FFSPeak.PlayerState.PlayerState.EnableCapturePlayerState = true;
			Logger.LogMessage((object)"Player state capture enabled on scene load.");
			if (ShouldLoadItems)
			{
				Logger.LogMessage((object)("Auto-loading items for map " + GetMapName()));
				AutoLoadItems.LoadItems(GetMapName());
			}
			DisableItems.RunDisableLogic();
			MapSceneReady = true;
			if (IsPlayer)
			{
				PlayerLeftOrJoinedDTO joined = new PlayerLeftOrJoinedDTO
				{
					PlayerName = LocalPlayerName,
					LevelName = GetMapName(),
					Joined = true
				};
				PlayerNetworkManager.SendPlayerLeftJoined(joined);
			}
			if (IsObserver)
			{
				Singleton<FreeCam>.Instance.HandleSceneLoaded();
				Singleton<FreeCam>.Instance.HandleMapLoaded();
				Singleton<LevelPlayerCountUIManager>.Instance.SetCurrentLevel(GetMapName());
				Singleton<LevelPlayerCountUIManager>.Instance.UpdateDisplay();
				_ = Singleton<ToolboxUIManager>.Instance;
				if (!NetworkManager.ObserverNetworkManager.IsConnected())
				{
					NetworkManager.ObserverNetworkManager.Connect();
				}
				Lava[] array = Object.FindObjectsByType<Lava>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				Lava[] array2 = array;
				foreach (Lava val in array2)
				{
					FieldInfo field = typeof(Lava).GetField("bounds", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						Bounds val2 = (Bounds)field.GetValue(val);
						Logger.LogInfo((object)$"Lava bounds for {((Object)val).name}: center={((Bounds)(ref val2)).center}, size={((Bounds)(ref val2)).size}, extents={((Bounds)(ref val2)).extents}");
					}
				}
			}
			Plugin.LevelLoaded?.Invoke(GetMapName());
		}

		private void OnLobbyJoined(ServerMessageDTO dTO)
		{
			LobbyCode = dTO.Data;
			Logger.LogMessage((object)("Joined lobby: " + LobbyCode));
		}

		private void OnSceneLoaded(Scene arg0, LoadSceneMode arg1)
		{
			Logger.LogInfo((object)("Loaded scene : [" + ((Scene)(ref arg0)).name + "]"));
			if (IsSceneLoaded("Title"))
			{
				Singleton<InputManager>.Instance.EnableInputs();
				ModChecker.Check();
				if (ModChecker.UnauthorizedMods.Count > 0)
				{
					Singleton<ForbiddenModUI>.Instance.Show(ModChecker.UnauthorizedMods);
				}
				if (IsOnMapScene)
				{
					if (IsPlayer)
					{
						PlayerLeftOrJoinedDTO joined = new PlayerLeftOrJoinedDTO
						{
							PlayerName = LocalPlayerName,
							LevelName = string.Empty,
							Joined = false
						};
						PlayerNetworkManager.SendPlayerLeftJoined(joined);
						ModChecker.StopCheckAsync();
						Logger.LogMessage((object)"Sent player left notification to server on returning to main menu.");
					}
					PlayerNetworkManager.SendJoinLobby(new JoinLobbyDTO("000000"));
				}
				if (IsObserver)
				{
					Singleton<PlayerListUIManager>.Instance.Clear();
					Singleton<PlayerListUIManager>.Instance.SetDisplay(show: false);
					((Behaviour)Singleton<PlayerListUIManager>.Instance).enabled = false;
					Singleton<LobbyManagerUIManager>.Instance.Hide();
					Singleton<RemotePlayerAdministrationUIManager>.Instance.Hide();
				}
			}
			if (IsSceneLoaded("Airport"))
			{
				Singleton<InputManager>.Instance.EnableInputs();
				SceneName = null;
				ModChecker.Check();
				if (ModChecker.UnauthorizedMods.Count > 0)
				{
					return;
				}
				IsInLobby = true;
				_ = Singleton<InputDisabledUI>.Instance;
				_ = Singleton<InputManager>.Instance;
				((MonoBehaviour)this).StartCoroutine(TryCapturePlayerName());
				((MonoBehaviour)this).StartCoroutine(InitializeNetworkManager());
				HeightBarsUIManager.Instance.Initialize();
				VersionString val = Object.FindFirstObjectByType<VersionString>();
				if ((Object)(object)val != (Object)null)
				{
					((Behaviour)val).enabled = false;
				}
				Singleton<FreeCam>.Instance.HandleSceneLoaded();
				if (IsObserver)
				{
					_ = Singleton<AdminCommandUIManager>.Instance;
					_ = Singleton<RemotePlayerAdministrationUIManager>.Instance;
					Singleton<LobbyManagerUIManager>.Instance.Show();
					Singleton<FreeCam>.Instance.ToggleFreeCam(forceEnable: true);
					LoadItemsOnNextMapLoad = true;
				}
				else
				{
					Singleton<JoinLobbyUI>.Instance.Show();
				}
				if (IsOnMapScene && IsObserver && NetworkManager.ObserverNetworkManager.IsConnected())
				{
					NetworkManager.ObserverNetworkManager.Disconnect();
					Logger.LogInfo((object)"Remote observer disabled on returning to lobby.");
				}
			}
			else
			{
				IsInLobby = false;
			}
			if (IsSceneLoaded("Level_"))
			{
				if (!IsOnMapScene)
				{
					IsOnMapScene = true;
					((MonoBehaviour)this).StartCoroutine(MapSceneLoaded());
				}
			}
			else
			{
				IsOnMapScene = false;
				LoadingLevel = false;
			}
		}

		private void OnSceneUnloaded(Scene arg0)
		{
			Logger.LogInfo((object)("Unloaded scene : [" + ((Scene)(ref arg0)).name + "]"));
			if (!IsSceneLoaded("Level_"))
			{
				MapSceneReady = false;
				IsOnMapScene = false;
				Singleton<InputDisabledUI>.Instance.Hide();
				FFSPeak.PlayerState.PlayerState.EnableCapturePlayerState = false;
				Logger.LogInfo((object)"Player state capture disabled on scene unload.");
			}
			if (!IsSceneLoaded("Airport"))
			{
				IsInLobby = false;
			}
		}
	}
	public abstract class Singleton<T> : MonoBehaviour where T : Singleton<T>
	{
		private static bool applicationIsQuitting = false;

		private static T instance;

		private bool isInitialized;

		private static readonly object @lock = new object();

		public static T Instance
		{
			get
			{
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Expected O, but got Unknown
				if (applicationIsQuitting)
				{
					return null;
				}
				lock (@lock)
				{
					if ((Object)(object)instance == (Object)null)
					{
						instance = Object.FindFirstObjectByType<T>();
						if ((Object)(object)instance == (Object)null)
						{
							GameObject val = new GameObject(typeof(T).Name);
							instance = val.AddComponent<T>();
							Object.DontDestroyOnLoad((Object)(object)val);
							if (!instance.isInitialized)
							{
								instance.Initialize();
								instance.isInitialized = true;
							}
						}
					}
					return instance;
				}
			}
		}

		protected virtual void Awake()
		{
			if ((Object)(object)instance != (Object)null && (Object)(object)instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			instance = (T)this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			if ((Object)(object)instance == (Object)(object)this && !isInitialized)
			{
				Initialize();
				isInitialized = true;
			}
		}

		protected virtual void Initialize()
		{
		}

		protected virtual void OnApplicationQuit()
		{
			applicationIsQuitting = true;
		}

		protected virtual void OnDestroy()
		{
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
}
namespace FFSPeak.Utils
{
	public static class ModChecker
	{
		public static readonly HashSet<string> AuthorizedGuids = new HashSet<string> { "com.github.flonou.FFSPeak", "com.github.flonou.Peak-ItemSpawnSync", "com.github.PEAKModding.PEAKLib.UI", "com.github.PEAKModding.PEAKLib.Core", "com.github.PEAKModding.SoftDependencyFix", "com.snosz.photoncustompropsutils", "com.turtledsr.peakversionbypass", "toastoverflow.EpilepsySafePEAK", "Linkoid.Peak.StableCamera" };

		public static readonly HashSet<string> ForbiddenExternalMods = new HashSet<string> { "WeMod", "Wand", "Cheat Engine" };

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

		private static bool checkThreadRunning = false;

		private static Thread checkThread;

		private static AutoResetEvent checkThreadStopEvent = new AutoResetEvent(initialState: false);

		public static IReadOnlyList<PluginInfo> UnauthorizedMods { get; private set; } = Array.Empty<PluginInfo>();

		public static void Check()
		{
			Plugin.Logger.LogMessage((object)"Running mod check against allowlist...");
			Plugin.Logger.LogMessage((object)("Plugins currently loaded: " + string.Join(", ", Chainloader.PluginInfos.Values.Select((PluginInfo p) => $"{p.Metadata.GUID} v{p.Metadata.Version}"))));
			UnauthorizedMods = Chainloader.PluginInfos.Values.Where((PluginInfo p) => !AuthorizedGuids.Contains(p.Metadata.GUID)).ToList();
			if (UnauthorizedMods.Count > 0)
			{
				Plugin.Logger.LogWarning((object)("[ModChecker] Unauthorized mod(s) detected: " + string.Join(", ", UnauthorizedMods.Select((PluginInfo p) => $"{p.Metadata.GUID} v{p.Metadata.Version}"))));
			}
			else
			{
				Plugin.Logger.LogMessage((object)"[ModChecker] All loaded mods are authorized.");
			}
		}

		public static void StartCheckAsync()
		{
			if (!checkThreadRunning)
			{
				checkThreadRunning = true;
				checkThread = new Thread(CheckLoop)
				{
					IsBackground = true
				};
				checkThread.Start();
			}
		}

		public static void StopCheckAsync()
		{
			if (checkThreadRunning)
			{
				checkThreadRunning = false;
				checkThreadStopEvent.Set();
				try
				{
					checkThread.Join(500);
				}
				catch
				{
				}
				checkThread = null;
			}
		}

		public static void CheckLoop()
		{
			while (checkThreadRunning)
			{
				foreach (string forbiddenExternalMod in ForbiddenExternalMods)
				{
					if (Process.GetProcessesByName(forbiddenExternalMod).Length != 0)
					{
						UnauthorizedModDTO unauthorizedMod = CreateUnauthorizedModDTO(forbiddenExternalMod);
						PlayerNetworkManager.SendUnauthorizedModDetected(unauthorizedMod);
					}
				}
				checkThreadStopEvent.WaitOne(30000);
			}
		}

		public static UnauthorizedModDTO CreateUnauthorizedModDTO(string modName)
		{
			return new UnauthorizedModDTO
			{
				PlayerName = Plugin.LocalPlayerName,
				ModName = modName,
				LevelName = Plugin.GetMapName()
			};
		}
	}
	public class PhotonCloneUtils : MonoBehaviourPun
	{
		private static PhotonCloneUtils instance;

		public static PhotonCloneUtils Instance
		{
			get
			{
				if ((Object)(object)instance == (Object)null)
				{
					if ((Object)(object)GameUtils.instance == (Object)null)
					{
						Plugin.Logger.LogWarning((object)"PhotonCloneUtils requires GameUtils.instance to exist");
						return null;
					}
					GameObject gameObject = ((Component)GameUtils.instance).gameObject;
					instance = gameObject.GetComponent<PhotonCloneUtils>();
					if ((Object)(object)instance == (Object)null)
					{
						instance = gameObject.AddComponent<PhotonCloneUtils>();
					}
				}
				return instance;
			}
		}

		public static GameObject CloneWithPhoton(GameObject source, Transform parent)
		{
			if ((Object)(object)source == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"CloneWithPhoton called with null source");
				return null;
			}
			if ((Object)(object)Instance == (Object)null)
			{
				return null;
			}
			if (!Instance.EnsurePhotonViewValid())
			{
				Plugin.Logger.LogWarning((object)"CloneWithPhoton requires a valid PhotonView on GameUtils (join a room first)");
				return null;
			}
			return Instance.CloneLocalAndRpc(source, parent);
		}

		private GameObject CloneLocalAndRpc(GameObject source, Transform parent)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			PhotonView component = source.GetComponent<PhotonView>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"CloneWithPhoton requires a PhotonView on the source object");
				return null;
			}
			int viewID = component.ViewID;
			int num = 0;
			if ((Object)(object)parent != (Object)null)
			{
				PhotonView component2 = ((Component)parent).GetComponent<PhotonView>();
				if ((Object)(object)component2 != (Object)null)
				{
					num = component2.ViewID;
				}
			}
			List<string> photonViewPaths = GetPhotonViewPaths(source.transform);
			if (photonViewPaths.Count == 0)
			{
				Plugin.Logger.LogWarning((object)"CloneWithPhoton found no PhotonViews in source hierarchy");
			}
			int[] array = AllocateViewIds(photonViewPaths.Count);
			int[] array2 = AllocateViewIds(photonViewPaths.Count);
			if (!EnsurePhotonViewValid())
			{
				Plugin.Logger.LogWarning((object)"CloneWithPhoton requires a valid PhotonView on GameUtils (join a room first)");
				return null;
			}
			((MonoBehaviourPun)this).photonView.RPC("RpcCloneWithPhoton", (RpcTarget)1, new object[7]
			{
				viewID,
				num,
				source.transform.position,
				source.transform.rotation,
				photonViewPaths.ToArray(),
				array,
				array2
			});
			return CloneLocal(source, parent, photonViewPaths, array, array2);
		}

		[PunRPC]
		private void RpcCloneWithPhoton(int sourceViewId, int parentViewId, Vector3 position, Quaternion rotation, string[] viewPaths, int[] originalIds, int[] cloneIds)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			PhotonView val = PhotonView.Find(sourceViewId);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogWarning((object)$"RpcCloneWithPhoton: source PhotonView {sourceViewId} not found");
				return;
			}
			Transform parent = null;
			if (parentViewId != 0)
			{
				PhotonView val2 = PhotonView.Find(parentViewId);
				if ((Object)(object)val2 != (Object)null)
				{
					parent = ((Component)val2).transform;
				}
			}
			CloneLocal(((Component)val).gameObject, parent, new List<string>(viewPaths), originalIds, cloneIds, position, rotation);
		}

		private static GameObject CloneLocal(GameObject source, Transform parent, List<string> viewPaths, int[] originalIds, int[] cloneIds, Vector3? positionOverride = null, Quaternion? rotationOverride = null)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			DisablePhotonViews(source.transform);
			Vector3 val = (Vector3)(((??)positionOverride) ?? source.transform.position);
			Quaternion val2 = (Quaternion)(((??)rotationOverride) ?? source.transform.rotation);
			GameObject val3 = Object.Instantiate<GameObject>(source, val, val2);
			if ((Object)(object)parent != (Object)null)
			{
				val3.transform.SetParent(parent, true);
			}
			RecreatePhotonViewsWithIds(source.transform, viewPaths, originalIds);
			RecreatePhotonViewsWithIds(val3.transform, viewPaths, cloneIds);
			return val3;
		}

		private static void DisablePhotonViews(Transform root)
		{
			PhotonView component = ((Component)root).GetComponent<PhotonView>();
			if ((Object)(object)component != (Object)null)
			{
				Plugin.Logger.LogInfo((object)$"Disabling existing PhotonView on root '{((Object)((Component)root).gameObject).name}' with ViewID {component.ViewID}");
				component.ViewID = 0;
			}
			PhotonView[] componentsInChildren = ((Component)root).GetComponentsInChildren<PhotonView>(true);
			foreach (PhotonView val in componentsInChildren)
			{
				Plugin.Logger.LogInfo((object)$"Disabling existing PhotonView on '{((Object)((Component)val).gameObject).name}' with ViewID {val.ViewID}");
				val.ViewID = 0;
			}
		}

		private static List<string> GetPhotonViewPaths(Transform root)
		{
			PhotonView[] componentsInChildren = ((Component)root).GetComponentsInChildren<PhotonView>(true);
			List<string> list = new List<string>(componentsInChildren.Length);
			PhotonView[] array = componentsInChildren;
			foreach (PhotonView val in array)
			{
				list.Add(GetRelativePath(root, ((Component)val).transform));
			}
			return list;
		}

		private static string GetRelativePath(Transform root, Transform target)
		{
			if ((Object)(object)root == (Object)(object)target)
			{
				return string.Empty;
			}
			List<string> list = new List<string>();
			Transform val = target;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			if ((Object)(object)val != (Object)(object)root)
			{
				return string.Empty;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		private static Transform FindByRelativePath(Transform root, string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return root;
			}
			return root.Find(path);
		}

		private static void RecreatePhotonViewsWithIds(Transform root, List<string> viewPaths, int[] viewIds)
		{
			DisablePhotonViews(root);
			if (viewIds == null || viewPaths.Count != viewIds.Length)
			{
				Plugin.Logger.LogWarning((object)"RecreatePhotonViewsWithIds: invalid mapping payload");
				return;
			}
			for (int i = 0; i < viewPaths.Count; i++)
			{
				Transform val = FindByRelativePath(root, viewPaths[i]);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Logger.LogWarning((object)("RecreatePhotonViewsWithIds: missing target transform for path '" + viewPaths[i] + "'"));
					continue;
				}
				if (viewIds[i] == 0)
				{
					Plugin.Logger.LogWarning((object)("RecreatePhotonViewsWithIds: invalid ViewID for path '" + viewPaths[i] + "'"));
					continue;
				}
				PhotonView component = ((Component)val).gameObject.GetComponent<PhotonView>();
				component.ViewID = viewIds[i];
				Plugin.Logger.LogInfo((object)$"Recreated PhotonView on '{((Object)val).name}' with ViewID {viewIds[i]} at path '{viewPaths[i]}'");
			}
		}

		private static int[] AllocateViewIds(int count)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			int[] array = new int[count];
			if (!PhotonNetwork.InRoom)
			{
				Plugin.Logger.LogWarning((object)"AllocateViewIds requires PhotonNetwork.InRoom");
				return array;
			}
			for (int i = 0; i < count; i++)
			{
				GameObject val = new GameObject("PhotonViewIdAllocator");
				PhotonView val2 = val.AddComponent<PhotonView>();
				bool flag = PhotonNetwork.AllocateViewID(val2);
				array[i] = (flag ? val2.ViewID : 0);
				Object.DestroyImmediate((Object)(object)val);
			}
			return array;
		}

		private bool EnsurePhotonViewValid()
		{
			if ((Object)(object)((MonoBehaviourPun)this).photonView == (Object)null)
			{
				return false;
			}
			if (PhotonNetwork.InRoom)
			{
				return ((MonoBehaviourPun)this).photonView.ViewID != 0;
			}
			return false;
		}
	}
	public class ScoreLogger : Singleton<ScoreLogger>
	{
		private float lastLogTime;

		public void LogScores()
		{
			if (!Plugin.ScoreLoggingEnabled || !Plugin.IsOnMapScene || (Object)(object)Singleton<RemotePlayerManager>.Instance == (Object)null || Singleton<RemotePlayerManager>.Instance.GetAllPlayers().Count() == 0)
			{
				return;
			}
			string text = Path.Combine(Plugin.ScoreLoggingFolderPath, "FFSPeak");
			Directory.CreateDirectory(text);
			string text2 = Path.Combine(text, $"Scores_{Plugin.GetMapName()}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.csv");
			using (StreamWriter streamWriter = new StreamWriter(text2))
			{
				streamWriter.WriteLine("Time; Player Name; State; Last Checkpoint; Max Score; Current Score; Finish Time");
				foreach (RemotePlayerData allPlayer in Singleton<RemotePlayerManager>.Instance.GetAllPlayers())
				{
					string text3 = (allPlayer.IsFinished ? "Finished" : (allPlayer.IsDead ? "Dead" : "In Progress"));
					streamWriter.WriteLine($" {DateTime.Now}; {allPlayer.PlayerName}; {text3}; {allPlayer.LastCheckpoint}; {allPlayer.MaxHeight.ToString(CultureInfo.InvariantCulture)}; {allPlayer.CurrentHeight.ToString(CultureInfo.InvariantCulture)} ; {allPlayer.FinishTime.ToString(CultureInfo.InvariantCulture)}");
				}
			}
			Plugin.Logger.LogMessage((object)("Scores logged to " + text2));
		}

		public void Update()
		{
			if (Plugin.ScoreLoggingEnabled && Plugin.IsOnMapScene && Time.time - lastLogTime >= Plugin.ScoreLoggingInterval)
			{
				LogScores();
				lastLogTime = Time.time;
			}
		}
	}
}
namespace FFSPeak.UI
{
	public class CheckpointTeleportUI : Singleton<CheckpointTeleportUI>
	{
		public static bool Enabled = false;

		private const KeyCode TOGGLE_KEY = (KeyCode)290;

		private const float SPAWN_HEIGHT_OFFSET = 1.5f;

		private static readonly KeyCode[] NumpadKeys;

		private static readonly FieldInfo IsInvincibleField;

		private ManualLogSource logger;

		private GameObject uiRoot;

		private Transform rowContainer;

		private readonly List<GameObject> rows = new List<GameObject>();

		private TextMeshProUGUI invincibilityStatusText;

		private bool _isInvincible;

		private readonly List<Transform> _checkpoints = new List<Transform>();

		public bool IsVisible
		{
			get
			{
				if ((Object)(object)uiRoot != (Object)null)
				{
					return uiRoot.activeSelf;
				}
				return false;
			}
		}

		protected override void Initialize()
		{
			logger = Plugin.Logger;
			BuildUI();
			logger.LogMessage((object)string.Format("{0} initialized (toggle: {1})", "CheckpointTeleportUI", (object)(KeyCode)290));
		}

		public void Refresh()
		{
			if (Enabled)
			{
				RebuildRows();
			}
		}

		private void Update()
		{
			if (!Enabled)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)290))
			{
				Toggle();
			}
			if (!Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)305))
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)271))
			{
				ToggleInvincible();
			}
			else
			{
				if (_checkpoints.Count == 0)
				{
					return;
				}
				for (int i = 0; i < NumpadKeys.Length && i < _checkpoints.Count; i++)
				{
					if (Input.GetKeyDown(NumpadKeys[i]))
					{
						TeleportTo(_checkpoints[i]);
						break;
					}
				}
			}
		}

		public void Show()
		{
			if ((Object)(object)uiRoot != (Object)null)
			{
				uiRoot.SetActive(true);
			}
		}

		public void Hide()
		{
			if ((Object)(object)uiRoot != (Object)null)
			{
				uiRoot.SetActive(false);
			}
		}

		public void Toggle()
		{
			if (!((Object)(object)uiRoot == (Object)null))
			{
				bool flag = !uiRoot.activeSelf;
				uiRoot.SetActive(flag);
				if (flag)
				{
					RebuildRows();
				}
			}
		}

		private void TeleportTo(Transform target)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null)
			{
				logger.LogWarning((object)"[CheckpointTeleportUI] Cannot teleport: localCharacter is null.");
				return;
			}
			Vector3 val = target.position + Vector3.up * 1.5f;
			localCharacter.WarpPlayerRPC(val, true);
			logger.LogMessage((object)string.Format("[{0}] Teleported to {1} → {2}", "CheckpointTeleportUI", ((Object)target).name, val));
		}

		private void ToggleInvincible()
		{
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || IsInvincibleField == null)
			{
				logger.LogWarning((object)"[CheckpointTeleportUI] Cannot toggle invincibility: localCharacter or field is null.");
				return;
			}
			_isInvincible = !_isInvincible;
			IsInvincibleField.SetValue(localCharacter.data, _isInvincible);
			UpdateInvincibilityLabel();
			logger.LogMessage((object)string.Format("[{0}] Invincibility: {1}", "CheckpointTeleportUI", _isInvincible));
		}

		private void UpdateInvincibilityLabel()
		{
			if (!((Object)(object)invincibilityStatusText == (Object)null))
			{
				((TMP_Text)invincibilityStatusText).text = (_isInvincible ? "<color=#AAAAAA>[Ctrl+NumEnter]</color>  God mode  <color=#44FF44>ON</color>" : "<color=#AAAAAA>[Ctrl+NumEnter]</color>  God mode  <color=#888888>OFF</color>");
			}
		}

		private void BuildUI()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Expected O, but got Unknown
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Expected O, but got Unknown
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Expected O, but got Unknown
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Expected O, but got Unknown
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			uiRoot = new GameObject("CheckpointTeleportUI");
			uiRoot.transform.SetParent(((Component)this).transform, false);
			Canvas val = uiRoot.AddComponent<Canvas>();
			val.renderMode = (RenderMode)0;
			val.sortingOrder = 200;
			CanvasScaler val2 = uiRoot.AddComponent<CanvasScaler>();
			val2.uiScaleMode = (ScaleMode)1;
			val2.referenceResolution = new Vector2(1920f, 1080f);
			val2.matchWidthOrHeight = 0.5f;
			GameObject val3 = new GameObject("Panel");
			val3.transform.SetParent(uiRoot.transform, false);
			RectTransform val4 = val3.AddComponent<RectTransform>();
			val4.anchorMin = new Vector2(1f, 1f);
			val4.anchorMax = new Vector2(1f, 1f);
			val4.pivot = new Vector2(1f, 1f);
			val4.anchoredPosition = new Vector2(-20f, -20f);
			val4.sizeDelta = new Vector2(300f, 0f);
			Image val5 = val3.AddComponent<Image>();
			((Graphic)val5).color = new Color(0f, 0f, 0f, 0.82f);
			VerticalLayoutGroup val6 = val3.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)val6).padding = new RectOffset(8, 8, 6, 8);
			((HorizontalOrVerticalLayoutGroup)val6).spacing = 4f;
			((HorizontalOrVerticalLayoutGroup)val6).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val6).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val6).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)val6).childForceExpandHeight = false;
			ContentSizeFitter val7 = val3.AddComponent<ContentSizeFitter>();
			val7.verticalFit = (FitMode)2;
			GameObject val8 = new GameObject("Header");
			val8.transform.SetParent(val3.transform, false);
			HorizontalLayoutGroup val9 = val8.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)val9).spacing = 6f;
			((LayoutGroup)val9).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)val9).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val9).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val9).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)val9).childForceExpandHeight = false;
			LayoutElement val10 = val8.AddComponent<LayoutElement>();
			val10.preferredHeight = 22f;
			GameObject val11 = new GameObject("Title");
			val11.transform.SetParent(val8.transform, false);
			LayoutElement val12 = val11.AddComponent<LayoutElement>();
			val12.flexibleWidth = 1f;
			TextMeshProUGUI val13 = val11.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val13).text = $"=> Checkpoints  [{(object)(KeyCode)290}]";
			((TMP_Text)val13).fontSize = 13f;
			((TMP_Text)val13).fontStyle = (FontStyles)1;
			((Graphic)val13).color = new Color(0.95f, 0.85f, 0.3f, 1f);
			((Graphic)val13).raycastTarget = false;
			GameObject val14 = new GameObject("Rows");
			val14.transform.SetParent(val3.transform, false);
			VerticalLayoutGroup val15 = val14.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)val15).spacing = 3f;
			((HorizontalOrVerticalLayoutGroup)val15).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val15).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val15).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)val15).childForceExpandHeight = false;
			ContentSizeFitter val16 = val14.AddComponent<ContentSizeFitter>();
			val16.verticalFit = (FitMode)2;
			rowContainer = val14.transform;
			GameObject val17 = new GameObject("Divider");
			val17.transform.SetParent(val3.transform, false);
			LayoutElement val18 = val17.AddComponent<LayoutElement>();
			val18.preferredHeight = 1f;
			Image val19 = val17.AddComponent<Image>();
			((Graphic)val19).color = new Color(0.5f, 0.5f, 0.5f, 0.4f);
			GameObject val20 = new GameObject("InvincibilityRow");
			val20.transform.SetParent(val3.transform, false);
			LayoutElement val21 = val20.AddComponent<LayoutElement>();
			val21.preferredHeight = 20f;
			invincibilityStatusText = val20.AddComponent<TextMeshProUGUI>();
			((TMP_Text)invincibilityStatusText).fontSize = 11f;
			((Graphic)invincibilityStatusText).color = Color.white;
			((Graphic)invincibilityStatusText).raycastTarget = false;
			UpdateInvincibilityLabel();
			uiRoot.SetActive(false);
			Plugin.Logger.LogMessage((object)"[CheckpointTeleportUI] UI built");
		}

		private void RebuildRows()
		{
			foreach (GameObject row in rows)
			{
				Object.Destroy((Object)(object)row);
			}
			rows.Clear();
			_checkpoints.Clear();
			if ((Object)(object)Singleton<CampfireManager>.Instance == (Object)null)
			{
				return;
			}
			Singleton<CampfireManager>.Instance.UpdateCampfires();
			int num = 0;
			foreach (Transform campfire in Singleton<CampfireManager>.Instance.GetCampfires())
			{
				if ((Object)(object)campfire == (Object)null)
				{
					num++;
					continue;
				}
				_checkpoints.Add(campfire);
				string labelText = BuildLabel(num, campfire);
				GameObject val = MakeRow(labelText);
				val.transform.SetParent(rowContainer, false);
				rows.Add(val);
				num++;
			}
		}

		private static string BuildLabel(int index, Transform cp)
		{
			string text = ((index == 0) ? "Spawn" : $"Camp {index}");
			string text2 = ((index < NumpadKeys.Length) ? $"<color=#AAAAAA>[Ctrl+Num{index}]</color>" : "");
			return text2 + "  " + text + "  <size=9><color=#666666>" + ((Object)cp).name + "</color></size>";
		}

		private GameObject MakeRow(string labelText)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Row");
			LayoutElement val2 = val.AddComponent<LayoutElement>();
			val2.preferredHeight = 20f;
			RectTransform val3 = val.AddComponent<RectTransform>();
			TextMeshProUGUI val4 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val4).text = labelText;
			((TMP_Text)val4).fontSize = 11f;
			((Graphic)val4).color = Color.white;
			((Graphic)val4).raycastTarget = false;
			((TMP_Text)val4).overflowMode = (TextOverflowModes)1;
			return val;
		}

		static CheckpointTeleportUI()
		{
			KeyCode[] array = new KeyCode[10];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			NumpadKeys = (KeyCode[])(object)array;
			IsInvincibleField = typeof(CharacterData).GetField("isInvincible", BindingFlags.Instance | BindingFlags.NonPublic);
		}
	}
	public class ForbiddenModUI : Singleton<ForbiddenModUI>
	{
		private GameObject uiContainer;

		private TextMeshProUGUI modListText;

		public void Show(IReadOnlyList<PluginInfo> unauthorizedMods)
		{
			if ((Object)(object)modListText != (Object)null)
			{
				((TMP_Text)modListText).text = string.Join("\n", unauthorizedMods.Select((PluginInfo p) => $"{p.Metadata.GUID}  v{p.Metadata.Version}"));
			}
			GameObject obj = uiContainer;
			if (obj != null)
			{
				obj.SetActive(true);
			}
		}

		public void Show(IReadOnlyList<string> forbiddenMods)
		{
			if ((Object)(object)modListText != (Object)null)
			{
				((TMP_Text)modListText).text = string.Join("\n", forbiddenMods);
			}
			GameObject obj = uiContainer;
			if (obj != null)
			{
				obj.SetActive(true);
			}
		}

		public void Hide()
		{
			GameObject obj = uiContainer;
			if (obj != null)
			{
				obj.SetActive(false);
			}
		}

		protected override void Initialize()
		{
			try
			{
				BuildUI();
				Hide();
				Plugin.Logger.LogMessage((object)"ForbiddenModUI initialized.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("[ForbiddenModUI] Init error: " + ex.Message + "\n" + ex.StackTrace));
			}
		}

		private void BuildUI()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			uiContainer = new GameObject("ForbiddenModUI");
			uiContainer.transform.SetParent(((Component)this).transform, false);
			Canvas val = uiContainer.AddComponent<Canvas>();
			val.renderMode = (RenderMode)0;
			val.sortingOrder = 600;
			CanvasScaler val2 = uiContainer.AddComponent<CanvasScaler>();
			val2.uiScaleMode = (ScaleMode)1;
			val2.referenceResolution = new Vector2(1920f, 1080f);
			GameObject val3 = new GameObject("Panel");
			val3.transform.SetParent(uiContainer.transform, false);
			RectTransform val4 = val3.AddComponent<RectTransform>();
			val4.anchorMin = new Vector2(0.5f, 0.5f);
			val4.anchorMax = new Vector2(0.5f, 0.5f);
			val4.pivot = new Vector2(0.5f, 0.5f);
			val4.anchoredPosition = Vector2.zero;
			val4.sizeDelta = new Vector2(900f, 240f);
			Image val5 = val3.AddComponent<Image>();
			((Graphic)val5).color = new Color(0.1f, 0f, 0f, 0.88f);
			PeakText val6 = MenuAPI.CreateText("⚠ FORBIDDEN MOD(S) DETECTED ⚠");
			((TMP_Text)val6.TextMesh).emojiFallbackSupport = true;
			((Component)val6).transform.SetParent(val3.transform, false);
			val6.SetColor(Color.red);
			val6.SetFontSize(28f);
			RectTransform component = ((Component)val6).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -12f);
			component.sizeDelta = new Vector2(0f, 40f);
			GameObject val7 = new GameObject("ModList");
			val7.transform.SetParent(val3.transform, false);
			RectTransform val8 = val7.AddComponent<RectTransform>();
			val8.anchorMin = new Vector2(0.05f, 0.05f);
			val8.anchorMax = new Vector2(0.95f, 0.65f);
			val8.offsetMin = Vector2.zero;
			val8.offsetMax = Vector2.zero;
			modListText = val7.AddComponent<TextMeshProUGUI>();
			((TMP_Text)modListText).fontSize = 18f;
			((Graphic)modListText).color = new Color(1f, 0.6f, 0.6f);
			((TMP_Text)modListText).alignment = (TextAlignmentOptions)514;
		}
	}
	public class FPSUI : Singleton<FPSUI>
	{
		private float deltaTime;

		private TextMeshProUGUI fpsText;

		private float timeSinceLastUpdate;

		private GameObject uiContainer;

		private float updateInterval = 0.5f;

		public void Hide()
		{
			GameObject obj = uiContainer;
			if (obj != null)
			{
				obj.SetActive(false);
			}
			((Behaviour)this).enabled = false;
		}

		public void Show()
		{
			GameObject obj = uiContainer;
			if (obj != null)
			{
				obj.SetActive(true);
			}
			((Behaviour)this).enabled = true;
		}

		public void Show(bool state)
		{
			GameObject obj = uiContainer;
			if (obj != null)
			{
				obj.SetActive(state);
			}
			((Behaviour)this).enabled = state;
		}

		public void ToggleShow()
		{
			Show(!((Behaviour)this).enabled);
		}

		protected override void Initialize()
		{
			CreateUI();
			Plugin.Logger.LogMessage((object)"FPSUI initialized");
			Hide();
		}

		protected void Update()
		{
			deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
			timeSinceLastUpdate += Time.unscaledDeltaTime;
			if (timeSinceLastUpdate >= updateInterval)
			{
				float fps = 1f / deltaTime;
				UpdateFPSDisplay(fps);
				timeSinceLastUpdate = 0f;
			}
		}

		private void CreateUI()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			uiContainer = new GameObject("FPSUI");
			uiContainer.transform.SetParent(((Component)this).transform, false);
			Canvas val = uiContainer.AddComponent<Canvas>();
			val.renderMode = (RenderMode)0;
			val.sortingOrder = 1000;
			GameObject val2 = new GameObject("FPSText");
			val2.transform.SetParent(uiContainer.transform, false);
			RectTransform val3 = val2.AddComponent<RectTransform>();
			val3.anchorMin = new Vector2(0f, 1f);
			val3.anchorMax = new Vector2(0f, 1f);
			val3.pivot = new Vector2(0f, 1f);
			val3.anchoredPosition = new Vector2(10f, -10f);
			val3.sizeDelta = new Vector2(150f, 40f);
			fpsText = val2.AddComponent<TextMeshProUGUI>();
			((TMP_Text)fpsText).fontSize = 24f;
			((TMP_Text)fpsText).fontStyle = (FontStyles)1;
			((TMP_Text)fpsText).alignment = (TextAlignmentOptions)257;
			((TMP_Text)fpsText).text = "FPS: --";
			((Graphic)fpsText).color = Color.white;
			((TMP_Text)fpsText).outlineWidth = 0.2f;
			((TMP_Text)fpsText).outlineColor = Color32.op_Implicit(Color.black);
		}

		private void UpdateFPSDisplay(float fps)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fpsText != (Object)null)
			{
				float num = Mathf.Ceil(fps);
				((TMP_Text)fpsText).text = $"FPS: {num}";
				((Graphic)fpsText).color = ((num >= 60f) ? new Color(0.3f, 1f, 0.3f) : ((num >= 30f) ? new Color(1f, 1f, 0.3f) : new Color(1f, 0.3f, 0.3f)));
			}
		}
	}
	public class HeightBarsUI : MonoBehaviour
	{
		public enum MarkerShape
		{
			Circle,
			Triangle
		}

		public Color barBorderColor = new Color(0.3f, 0.6f, 1f, 0.9f);

		public Color barBottomColor = new Color(0.1f, 0.2f, 0.4f, 0.8f);

		public Color barTopColor = new Color(0.2f, 0.4f, 0.8f, 0.8f);

		public Color markerColor = new Color(0.2f, 0.8f, 1f, 0.9f);

		public Color markerOutlineColor = new Color(1f, 1f, 1f, 1f);

		public MarkerShape markerShape;

		private ManualLogSource _logger;

		private RectTransform barBackground;

		private Transform labelsContainer;

		private GameObject markerPrefab;

		private Transform markersContainer;

		private float maxHeightScale = 400f;

		private Dictionary<string, PlayerHeightBar> playerMarkers = new Dictionary<string, PlayerHeightBar>();

		private Transform scaleLabelsContainer;

		private float maxDisplayHeight;

		private float minDisplayHeight;

		private float heightRange;

		private GameObject timerObj;

		private TextMeshProUGUI timerLabel;

		private float currentTimeLimit = -1f;

		private bool isExpanded;

		private Image barBgImage;

		private Sprite bar1DSprite;

		private Sprite bar2DSprite;

		private float minDisplayX;

		private float maxDisplayX;

		private float xRange;

		private Transform xAxisLabelsContainer;

		private Transform scaleLabels2DContainer;

		private TextMeshProUGUI modeHintLabel;

		private PlayerHeightBar currentSelectedPlayerMarker;

		private List<float> heights;

		private List<PlayerHeightBar> _sortedMarkers = new List<PlayerHeightBar>();

		private static readonly Comparison<PlayerHeightBar> _heightAscending = (PlayerHeightBar a, PlayerHeightBar b) => a.GetCurrentHeight().CompareTo(b.GetCurrentHeight());

		private int cachedMinZone = -1;

		private int cachedMaxZone = -1;

		public bool IsExpanded => isExpanded;

		public void ClearAllBars()
		{
			foreach (PlayerHeightBar value in playerMarkers.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
			}
			playerMarkers.Clear();
		}

		public void Initialize(ManualLogSource logger)
		{
			_logger = logger;
			CreateUI();
		}

		public void RegenerateScaleLabels(IEnumerable<Transform> heightObjects)
		{
			if ((Object)(object)labelsContainer == (Object)null)
			{
				_logger.LogWarning((object)"Cannot regenerate scale labels - bar not initialized");
				return;
			}
			CreateScaleLabels(heightObjects);
			_logger.LogMessage((object)$"Regenerated scale labels from {heightObjects.Count()} objects");
		}

		public void RemovePlayer(string playerName)
		{
			if (playerMarkers.ContainsKey(playerName))
			{
				Object.Destroy((Object)(object)((Component)playerMarkers[playerName]).gameObject);
				playerMarkers.Remove(playerName);
			}
		}

		public void UpdateTimer(float remainingTime)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			currentTimeLimit = Mathf.Max(0f, remainingTime);
			if (!((Object)(object)timerLabel != (Object)null))
			{
				return;
			}
			if (currentTimeLimit < 0f || !Plugin.IsOnMapScene)
			{
				timerObj.SetActive(false);
				return;
			}
			TimeSpan timeSpan = TimeSpan.FromSeconds(currentTimeLimit);
			if (Plugin.IsPlayer)
			{
				float num = (((Object)(object)FFSPeak.PlayerState.PlayerState.PlayerCharacter != (Object)null && FFSPeak.PlayerState.PlayerState.CurrentPlayerState != null) ? RemotePlayerData.GetCurrentHeight(FFSPeak.PlayerState.PlayerState.PlayerCharacter.data.dead, FFSPeak.PlayerState.PlayerState.CurrentPlayerState.IsFinished, FFSPeak.PlayerState.PlayerState.CurrentPlayerState.Position, FFSPeak.PlayerState.PlayerState.CurrentPlayerState.LastCheckpoint) : 0f);
				((TMP_Text)timerLabel).text = $"Time: {timeSpan.Hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2} - Score: {num:F1}";
			}
			else
			{
				((TMP_Text)timerLabel).text = $"Time: {timeSpan.Hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
			}
			if (!timerObj.activeSelf)
			{
				timerObj.SetActive(true);
			}
		}

		public void UpdatePlayer(RemotePlayerData playerData)
		{
			if (!playerMarkers.TryGetValue(playerData.PlayerName, out var value))
			{
				if ((Object)(object)markerPrefab == (Object)null)
				{
					markerPrefab = CreateMarkerPrefab();
				}
				GameObject val = Object.Instantiate<GameObject>(markerPrefab, markersContainer);
				value = val.GetComponent<PlayerHeightBar>();
				value.Initialize(playerData);
				playerMarkers[playerData.PlayerName] = value;
				_logger.LogMessage((object)("Created marker for " + playerData.PlayerName));
			}
			value.UpdateData();
		}

		private void LateUpdate()
		{
			UpdateVisibleZoneRange();
			UpdateMarkerPositions();
			UpdateTimer(currentTimeLimit - Time.deltaTime);
		}

		private GameObject CreateMarkerPrefab()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_001d: 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_0032: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Expected O, but got Unknown
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("PlayerMarker");
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.sizeDelta = new Vector2(200f, 30f);
			GameObject val3 = new GameObject("Background");
			val3.transform.SetParent(val.transform, false);
			RectTransform val4 = val3.AddComponent<RectTransform>();
			val4.anchorMin = new Vector2(0f, 0.5f);
			val4.anchorMax = new Vector2(0f, 0.5f);
			val4.pivot = new Vector2(0f, 0.5f);
			val4.anchoredPosition = new Vector2(-12f, 0f);
			val4.sizeDelta = new Vector2(32f, 32f);
			Image val5 = val3.AddComponent<Image>();
			Texture2D val6 = GenerateMarkerTexture(32, markerShape);
			Sprite sprite = Sprite.Create(val6, new Rect(0f, 0f, (float)((Texture)val6).width, (float)((Texture)val6).height), new Vector2(0.5f, 0.5f));
			val5.sprite = sprite;
			GameObject val7 = new GameObject("Checkpoint");
			val7.transform.SetParent(val.transform, false);
			RectTransform val8 = val7.AddComponent<RectTransform>();
			val8.anchorMin = new Vector2(0f, 0.5f);
			val8.anchorMax = new Vector2(0f, 0.5f);
			val8.pivot = new Vector2(0f, 0.5f);
			val8.anchoredPosition = new Vector2(0f, 0f);
			val8.sizeDelta = new Vector2(40f, 10f);
			TextMeshProUGUI val9 = val7.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val9).alignment = (TextAlignmentOptions)513;
			((TMP_Text)val9).fontSize = 14f;
			((Graphic)val9).color = Color.white;
			GameObject val10 = new GameObject("PlayerName");
			val10.transform.SetParent(val.transform, false);
			RectTransform val11 = val10.AddComponent<RectTransform>();
			val11.anchorMin = new Vector2(0f, 0.5f);
			val11.anchorMax = new Vector2(0f, 0.5f);
			val11.pivot = new Vector2(0f, 0.5f);
			val11.anchoredPosition = new Vector2(22f, 0f);
			val11.sizeDelta = new Vector2(200f, 0f);
			TextMeshProUGUI val12 = val10.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val12).alignment = (TextAlignmentOptions)513;
			((TMP_Text)val12).fontSize = 14f;
			((Graphic)val12).color = Color.white;
			((TMP_Text)val12).fontStyle = (FontStyles)1;
			PlayerHeightBar playerHeightBar = val.AddComponent<PlayerHeightBar>();
			playerHeightBar.playerNameText = val12;
			playerHeightBar.checkpointText = val9;
			playerHeightBar.markerImage = val5;
			return val;
		}

		private void CreateScaleLabels(IEnumerable<Transform> heightObjects)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			heights = new List<float>();
			List<Transform> list = heightObjects.ToList();
			float num = 0f;
			heights.Add(0f);
			for (int i = 1; i < list.Count; i++)
			{
				if ((Object)(object)list[i] != (Object)null && (Object)(object)list[i - 1] != (Object)null)
				{
					Vector3 position = list[i - 1].position;
					Vector3 position2 = list[i].position;
					float num2 = position2.y - position.y;
					float num3 = position2.z - position.z;
					num += Mathf.Sqrt(num2 * num2 + num3 * num3) * CharacterStats.unitsToMeters;
				}
				heights.Add(num);
			}
			if (heights.Count == 0)
			{
				heights.Add(0f);
			}
			minDisplayHeight = 0f;
			maxDisplayHeight = ((heights.Count > 0) ? heights.Max() : maxHeightScale);
			if (maxDisplayHeight < 1f)
			{
				maxDisplayHeight = maxHeightScale;
			}
			heightRange = maxDisplayHeight - minDisplayHeight;
			minDisplayX = -250f;
			maxDisplayX = 250f;
			xRange = maxDisplayX - minDisplayX;
			cachedMinZone = 0;
			cachedMaxZone = Mathf.Max(0, heights.Count - 2);
			RebuildScaleLabelDisplay(cachedMinZone, cachedMaxZone);
			Create2DYAxisLabels();
		}

		private int GetZoneIndex(float height)
		{
			if (heights == null || heights.Count < 2)
			{
				return 0;
			}
			for (int num = heights.Count - 2; num >= 0; num--)
			{
				if (height >= heights[num])
				{
					return num;
				}
			}
			return 0;
		}

		private (int minZone, int maxZone) ComputeVisibleZoneRange()
		{
			int item = Mathf.Max(0, (heights?.Count ?? 1) - 2);
			if (heights == null || heights.Count < 2 || playerMarkers.Count == 0)
			{
				return (minZone: 0, maxZone: item);
			}
			int num = int.MaxValue;
			int num2 = int.MinValue;
			foreach (PlayerHeightBar value in playerMarkers.Values)
			{
				int zoneIndex = GetZoneIndex(value.GetCurrentHeight());
				if (zoneIndex < num)
				{
					num = zoneIndex;
				}
				if (zoneIndex > num2)
				{
					num2 = zoneIndex;
				}
			}
			if (num == int.MaxValue)
			{
				return (minZone: 0, maxZone: item);
			}
			return (minZone: num, maxZone: num2);
		}

		private void UpdateVisibleZoneRange()
		{
			if (heights != null && heights.Count >= 2)
			{
				var (num, num2) = ComputeVisibleZoneRange();
				if (num != cachedMinZone || num2 != cachedMaxZone)
				{
					cachedMinZone = num;
					cachedMaxZone = num2;
					minDisplayHeight = heights[num];
					maxDisplayHeight = heights[Mathf.Min(num2 + 1, heights.Count - 1)];
					heightRange = Mathf.Max(0.01f, maxDisplayHeight - minDisplayHeight);
					RebuildScaleLabelDisplay(num, num2);
					Create2DYAxisLabels();
				}
			}
		}

		private void RebuildScaleLabelDisplay(int visibleMinZone, int visibleMaxZone)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)labelsContainer == (Object)null)
			{
				return;
			}
			if ((Object)(object)scaleLabelsContainer != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)scaleLabelsContainer).gameObject);
			}
			bool expanded = isExpanded;
			SetExpanded(expanded: false);
			GameObject val = new GameObject("ScaleLabels");
			val.transform.SetParent(labelsContainer, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			scaleLabelsContainer = val.transform;
			if (heights != null && heights.Count != 0)
			{
				int num = Mathf.Clamp(visibleMinZone, 0, heights.Count - 1);
				int num2 = Mathf.Clamp(visibleMaxZone + 1, 0, heights.Count - 1);
				for (int i = num; i <= num2; i++)
				{
					float num3 = heights[i];
					float num4 = ((heightRange > 0f) ? ((num3 - minDisplayHeight) / heightRange) : 0f);
					GameObject val3 = new GameObject($"Scale_{num3:F1}m");
					val3.transform.SetParent(scaleLabelsContainer, false);
					RectTransform val4 = val3.AddComponent<RectTransform>();
					val4.anchorMin = new Vector2(0f, num4);
					val4.anchorMax = new Vector2(1f, num4);
					val4.pivot = new Vector2(0.5f, 0.5f);
					val4.anchoredPosition = new Vector2(-40f, 0f);
					val4.sizeDelta = new Vector2(60f, 20f);
					TextMeshProUGUI val5 = val3.AddComponent<TextMeshProUGUI>();
					((TMP_Text)val5).text = $"{num3:F0}m - {i}";
					((TMP_Text)val5).fontSize = 12f;
					((Graphic)val5).color = Color.gray;
					((TMP_Text)val5).alignment = (TextAlignmentOptions)514;
				}
				SetExpanded(expanded);
			}
		}

		private void CreateUI()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Expected O, but got Unknown
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Expected O, but got Unknown
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Expected O, but got Unknown
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Expected O, but got Unknown
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown res

plugins/Google.Protobuf.dll

Decompiled 3 days ago
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf.Collections;
using Google.Protobuf.Reflection;
using Google.Protobuf.WellKnownTypes;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a17c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dcb6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665c5ae9cb6")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyMetadata("IsTrimmable", "True")]
[assembly: AssemblyCompany("Google Inc.")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright 2015, Google Inc.")]
[assembly: AssemblyDescription("C# runtime library for Protocol Buffers - Google's data interchange format.")]
[assembly: AssemblyFileVersion("3.27.4.0")]
[assembly: AssemblyInformationalVersion("3.27.4+80d48ae92d3007caac5eab0a8f8ee4e57f3a921e")]
[assembly: AssemblyProduct("Google.Protobuf")]
[assembly: AssemblyTitle("Google Protocol Buffers")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/protocolbuffers/protobuf.git")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.27.4.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsByRefLikeAttribute : Attribute
	{
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, Inherited = false)]
	internal sealed class DynamicallyAccessedMembersAttribute : Attribute
	{
		public DynamicallyAccessedMemberTypes MemberTypes { get; }

		public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
		{
			MemberTypes = memberTypes;
		}
	}
	[Flags]
	internal enum DynamicallyAccessedMemberTypes
	{
		None = 0,
		PublicParameterlessConstructor = 1,
		PublicConstructors = 3,
		NonPublicConstructors = 4,
		PublicMethods = 8,
		NonPublicMethods = 0x10,
		PublicFields = 0x20,
		NonPublicFields = 0x40,
		PublicNestedTypes = 0x80,
		NonPublicNestedTypes = 0x100,
		PublicProperties = 0x200,
		NonPublicProperties = 0x400,
		PublicEvents = 0x800,
		NonPublicEvents = 0x1000,
		Interfaces = 0x2000,
		All = -1
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Method, Inherited = false)]
	internal sealed class RequiresUnreferencedCodeAttribute : Attribute
	{
		public string Message { get; }

		public string Url { get; set; }

		public RequiresUnreferencedCodeAttribute(string message)
		{
			Message = message;
		}
	}
	[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
	internal sealed class UnconditionalSuppressMessageAttribute : Attribute
	{
		public string Category { get; }

		public string CheckId { get; }

		public string Scope { get; set; }

		public string Target { get; set; }

		public string MessageId { get; set; }

		public string Justification { get; set; }

		public UnconditionalSuppressMessageAttribute(string category, string checkId)
		{
			Category = category;
			CheckId = checkId;
		}
	}
}
namespace Google.Protobuf
{
	internal static class ByteArray
	{
		private const int CopyThreshold = 12;

		internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
		{
			if (count > 12)
			{
				Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count);
				return;
			}
			int num = srcOffset + count;
			for (int i = srcOffset; i < num; i++)
			{
				dst[dstOffset++] = src[i];
			}
		}

		internal static void Reverse(byte[] bytes)
		{
			int num = 0;
			int num2 = bytes.Length - 1;
			while (num < num2)
			{
				byte b = bytes[num];
				bytes[num] = bytes[num2];
				bytes[num2] = b;
				num++;
				num2--;
			}
		}
	}
	[SecuritySafeCritical]
	[DebuggerDisplay("Length = {Length}")]
	[DebuggerTypeProxy(typeof(ByteStringDebugView))]
	public sealed class ByteString : IEnumerable<byte>, IEnumerable, IEquatable<ByteString>
	{
		private sealed class ByteStringDebugView
		{
			private readonly ByteString data;

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public byte[] Items => data.bytes.ToArray();

			public ByteStringDebugView(ByteString data)
			{
				this.data = data;
			}
		}

		private static readonly ByteString empty = new ByteString(new byte[0]);

		private readonly ReadOnlyMemory<byte> bytes;

		public static ByteString Empty => empty;

		public int Length => bytes.Length;

		public bool IsEmpty => Length == 0;

		public ReadOnlySpan<byte> Span => bytes.Span;

		public ReadOnlyMemory<byte> Memory => bytes;

		public byte this[int index] => bytes.Span[index];

		internal static ByteString AttachBytes(ReadOnlyMemory<byte> bytes)
		{
			return new ByteString(bytes);
		}

		internal static ByteString AttachBytes(byte[] bytes)
		{
			return AttachBytes(bytes.AsMemory());
		}

		private ByteString(ReadOnlyMemory<byte> bytes)
		{
			this.bytes = bytes;
		}

		public byte[] ToByteArray()
		{
			return bytes.ToArray();
		}

		public string ToBase64()
		{
			if (MemoryMarshal.TryGetArray(bytes, out var segment))
			{
				return Convert.ToBase64String(segment.Array, segment.Offset, segment.Count);
			}
			return Convert.ToBase64String(bytes.ToArray());
		}

		public static ByteString FromBase64(string bytes)
		{
			if (!(bytes == ""))
			{
				return new ByteString(Convert.FromBase64String(bytes));
			}
			return Empty;
		}

		public static ByteString FromStream(Stream stream)
		{
			ProtoPreconditions.CheckNotNull(stream, "stream");
			MemoryStream memoryStream = new MemoryStream(stream.CanSeek ? checked((int)(stream.Length - stream.Position)) : 0);
			stream.CopyTo(memoryStream);
			return AttachBytes(memoryStream.ToArray());
		}

		public static Task<ByteString> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
		{
			ProtoPreconditions.CheckNotNull(stream, "stream");
			return ByteStringAsync.FromStreamAsyncCore(stream, cancellationToken);
		}

		public static ByteString CopyFrom(params byte[] bytes)
		{
			return new ByteString((byte[])bytes.Clone());
		}

		public static ByteString CopyFrom(byte[] bytes, int offset, int count)
		{
			byte[] array = new byte[count];
			ByteArray.Copy(bytes, offset, array, 0, count);
			return new ByteString(array);
		}

		public static ByteString CopyFrom(ReadOnlySpan<byte> bytes)
		{
			return new ByteString(bytes.ToArray());
		}

		public static ByteString CopyFrom(string text, Encoding encoding)
		{
			return new ByteString(encoding.GetBytes(text));
		}

		public static ByteString CopyFromUtf8(string text)
		{
			return CopyFrom(text, Encoding.UTF8);
		}

		public string ToString(Encoding encoding)
		{
			if (MemoryMarshal.TryGetArray(bytes, out var segment))
			{
				return encoding.GetString(segment.Array, segment.Offset, segment.Count);
			}
			byte[] array = bytes.ToArray();
			return encoding.GetString(array, 0, array.Length);
		}

		public string ToStringUtf8()
		{
			return ToString(Encoding.UTF8);
		}

		[SecuritySafeCritical]
		public IEnumerator<byte> GetEnumerator()
		{
			return MemoryMarshal.ToEnumerable(bytes).GetEnumerator();
		}

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

		public CodedInputStream CreateCodedInput()
		{
			if (MemoryMarshal.TryGetArray(bytes, out var segment) && segment.Count == bytes.Length)
			{
				return new CodedInputStream(segment.Array, segment.Offset, segment.Count);
			}
			return new CodedInputStream(bytes.ToArray());
		}

		public static bool operator ==(ByteString lhs, ByteString rhs)
		{
			if ((object)lhs == rhs)
			{
				return true;
			}
			if ((object)lhs == null || (object)rhs == null)
			{
				return false;
			}
			return lhs.bytes.Span.SequenceEqual(rhs.bytes.Span);
		}

		public static bool operator !=(ByteString lhs, ByteString rhs)
		{
			return !(lhs == rhs);
		}

		[SecuritySafeCritical]
		public override bool Equals(object obj)
		{
			return this == obj as ByteString;
		}

		[SecuritySafeCritical]
		public override int GetHashCode()
		{
			ReadOnlySpan<byte> span = bytes.Span;
			int num = 23;
			for (int i = 0; i < span.Length; i++)
			{
				num = num * 31 + span[i];
			}
			return num;
		}

		public bool Equals(ByteString other)
		{
			return this == other;
		}

		public void CopyTo(byte[] array, int position)
		{
			bytes.CopyTo(array.AsMemory(position));
		}

		public void WriteTo(Stream outputStream)
		{
			if (MemoryMarshal.TryGetArray(bytes, out var segment))
			{
				outputStream.Write(segment.Array, segment.Offset, segment.Count);
				return;
			}
			byte[] array = bytes.ToArray();
			outputStream.Write(array, 0, array.Length);
		}
	}
	internal static class ByteStringAsync
	{
		internal static async Task<ByteString> FromStreamAsyncCore(Stream stream, CancellationToken cancellationToken)
		{
			int capacity = (stream.CanSeek ? checked((int)(stream.Length - stream.Position)) : 0);
			MemoryStream memoryStream = new MemoryStream(capacity);
			await stream.CopyToAsync(memoryStream, 81920, cancellationToken);
			return ByteString.AttachBytes((memoryStream.Length == memoryStream.Capacity) ? memoryStream.GetBuffer() : memoryStream.ToArray());
		}
	}
	[SecuritySafeCritical]
	public sealed class CodedInputStream : IDisposable
	{
		private readonly bool leaveOpen;

		private readonly byte[] buffer;

		private readonly Stream input;

		private ParserInternalState state;

		internal const int DefaultRecursionLimit = 100;

		internal const int DefaultSizeLimit = int.MaxValue;

		internal const int BufferSize = 4096;

		public long Position
		{
			get
			{
				if (input != null)
				{
					return input.Position - (state.bufferSize + state.bufferSizeAfterLimit - state.bufferPos);
				}
				return state.bufferPos;
			}
		}

		internal uint LastTag => state.lastTag;

		public int SizeLimit => state.sizeLimit;

		public int RecursionLimit => state.recursionLimit;

		internal bool DiscardUnknownFields
		{
			get
			{
				return state.DiscardUnknownFields;
			}
			set
			{
				state.DiscardUnknownFields = value;
			}
		}

		internal ExtensionRegistry ExtensionRegistry
		{
			get
			{
				return state.ExtensionRegistry;
			}
			set
			{
				state.ExtensionRegistry = value;
			}
		}

		internal byte[] InternalBuffer => buffer;

		internal Stream InternalInputStream => input;

		internal ref ParserInternalState InternalState => ref state;

		internal bool ReachedLimit => SegmentedBufferHelper.IsReachedLimit(ref state);

		public bool IsAtEnd
		{
			get
			{
				ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
				return SegmentedBufferHelper.IsAtEnd(ref readOnlySpan, ref state);
			}
		}

		public CodedInputStream(byte[] buffer)
			: this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, leaveOpen: true)
		{
		}

		public CodedInputStream(byte[] buffer, int offset, int length)
			: this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, leaveOpen: true)
		{
			if (offset < 0 || offset > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
			}
			if (length < 0 || offset + length > buffer.Length)
			{
				throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
			}
		}

		public CodedInputStream(Stream input)
			: this(input, leaveOpen: false)
		{
		}

		public CodedInputStream(Stream input, bool leaveOpen)
			: this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[4096], 0, 0, leaveOpen)
		{
		}

		internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen)
		{
			this.input = input;
			this.buffer = buffer;
			state.bufferPos = bufferPos;
			state.bufferSize = bufferSize;
			state.sizeLimit = int.MaxValue;
			state.recursionLimit = 100;
			SegmentedBufferHelper.Initialize(this, out state.segmentedBufferHelper);
			this.leaveOpen = leaveOpen;
			state.currentLimit = int.MaxValue;
		}

		internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen)
			: this(input, buffer, bufferPos, bufferSize, leaveOpen)
		{
			if (sizeLimit <= 0)
			{
				throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");
			}
			if (recursionLimit <= 0)
			{
				throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");
			}
			state.sizeLimit = sizeLimit;
			state.recursionLimit = recursionLimit;
		}

		public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)
		{
			return new CodedInputStream(input, new byte[4096], 0, 0, sizeLimit, recursionLimit, leaveOpen: false);
		}

		public void Dispose()
		{
			if (!leaveOpen)
			{
				input.Dispose();
			}
		}

		internal void CheckReadEndOfStreamTag()
		{
			ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref state);
		}

		public uint PeekTag()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.PeekTag(ref readOnlySpan, ref state);
		}

		public uint ReadTag()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseTag(ref readOnlySpan, ref state);
		}

		public void SkipLastField()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			ParsingPrimitivesMessages.SkipLastField(ref readOnlySpan, ref state);
		}

		internal void SkipGroup(uint startGroupTag)
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			ParsingPrimitivesMessages.SkipGroup(ref readOnlySpan, ref state, startGroupTag);
		}

		public double ReadDouble()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseDouble(ref readOnlySpan, ref state);
		}

		public float ReadFloat()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseFloat(ref readOnlySpan, ref state);
		}

		public ulong ReadUInt64()
		{
			return ReadRawVarint64();
		}

		public long ReadInt64()
		{
			return (long)ReadRawVarint64();
		}

		public int ReadInt32()
		{
			return (int)ReadRawVarint32();
		}

		public ulong ReadFixed64()
		{
			return ReadRawLittleEndian64();
		}

		public uint ReadFixed32()
		{
			return ReadRawLittleEndian32();
		}

		public bool ReadBool()
		{
			return ReadRawVarint64() != 0;
		}

		public string ReadString()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ReadString(ref readOnlySpan, ref state);
		}

		public void ReadMessage(IMessage builder)
		{
			ParseContext.Initialize(buffer.AsSpan(), ref state, out var ctx);
			try
			{
				ParsingPrimitivesMessages.ReadMessage(ref ctx, builder);
			}
			finally
			{
				ctx.CopyStateTo(this);
			}
		}

		public void ReadGroup(IMessage builder)
		{
			ParseContext.Initialize(this, out var ctx);
			try
			{
				ParsingPrimitivesMessages.ReadGroup(ref ctx, builder);
			}
			finally
			{
				ctx.CopyStateTo(this);
			}
		}

		public ByteString ReadBytes()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ReadBytes(ref readOnlySpan, ref state);
		}

		public uint ReadUInt32()
		{
			return ReadRawVarint32();
		}

		public int ReadEnum()
		{
			return (int)ReadRawVarint32();
		}

		public int ReadSFixed32()
		{
			return (int)ReadRawLittleEndian32();
		}

		public long ReadSFixed64()
		{
			return (long)ReadRawLittleEndian64();
		}

		public int ReadSInt32()
		{
			return ParsingPrimitives.DecodeZigZag32(ReadRawVarint32());
		}

		public long ReadSInt64()
		{
			return ParsingPrimitives.DecodeZigZag64(ReadRawVarint64());
		}

		public int ReadLength()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseLength(ref readOnlySpan, ref state);
		}

		public bool MaybeConsumeTag(uint tag)
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.MaybeConsumeTag(ref readOnlySpan, ref state, tag);
		}

		internal uint ReadRawVarint32()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseRawVarint32(ref readOnlySpan, ref state);
		}

		internal static uint ReadRawVarint32(Stream input)
		{
			return ParsingPrimitives.ReadRawVarint32(input);
		}

		internal ulong ReadRawVarint64()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseRawVarint64(ref readOnlySpan, ref state);
		}

		internal uint ReadRawLittleEndian32()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseRawLittleEndian32(ref readOnlySpan, ref state);
		}

		internal ulong ReadRawLittleEndian64()
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ParseRawLittleEndian64(ref readOnlySpan, ref state);
		}

		internal int PushLimit(int byteLimit)
		{
			return SegmentedBufferHelper.PushLimit(ref state, byteLimit);
		}

		internal void PopLimit(int oldLimit)
		{
			SegmentedBufferHelper.PopLimit(ref state, oldLimit);
		}

		internal byte[] ReadRawBytes(int size)
		{
			ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(buffer);
			return ParsingPrimitives.ReadRawBytes(ref readOnlySpan, ref state, size);
		}

		public void ReadRawMessage(IMessage message)
		{
			ParseContext.Initialize(this, out var ctx);
			try
			{
				ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);
			}
			finally
			{
				ctx.CopyStateTo(this);
			}
		}
	}
	[SecuritySafeCritical]
	public sealed class CodedOutputStream : IDisposable
	{
		public sealed class OutOfSpaceException : IOException
		{
			internal OutOfSpaceException()
				: base("CodedOutputStream was writing to a flat byte array and ran out of space.")
			{
			}
		}

		private const int LittleEndian64Size = 8;

		private const int LittleEndian32Size = 4;

		internal const int DoubleSize = 8;

		internal const int FloatSize = 4;

		internal const int BoolSize = 1;

		public static readonly int DefaultBufferSize = 4096;

		private readonly bool leaveOpen;

		private readonly byte[] buffer;

		private WriterInternalState state;

		private readonly Stream output;

		public long Position
		{
			get
			{
				if (output != null)
				{
					return output.Position + state.position;
				}
				return state.position;
			}
		}

		public bool Deterministic { get; set; }

		public int SpaceLeft => WriteBufferHelper.GetSpaceLeft(ref state);

		internal byte[] InternalBuffer => buffer;

		internal Stream InternalOutputStream => output;

		internal ref WriterInternalState InternalState => ref state;

		public static int ComputeDoubleSize(double value)
		{
			return 8;
		}

		public static int ComputeFloatSize(float value)
		{
			return 4;
		}

		public static int ComputeUInt64Size(ulong value)
		{
			return ComputeRawVarint64Size(value);
		}

		public static int ComputeInt64Size(long value)
		{
			return ComputeRawVarint64Size((ulong)value);
		}

		public static int ComputeInt32Size(int value)
		{
			if (value >= 0)
			{
				return ComputeRawVarint32Size((uint)value);
			}
			return 10;
		}

		public static int ComputeFixed64Size(ulong value)
		{
			return 8;
		}

		public static int ComputeFixed32Size(uint value)
		{
			return 4;
		}

		public static int ComputeBoolSize(bool value)
		{
			return 1;
		}

		public static int ComputeStringSize(string value)
		{
			int byteCount = WritingPrimitives.Utf8Encoding.GetByteCount(value);
			return ComputeLengthSize(byteCount) + byteCount;
		}

		public static int ComputeGroupSize(IMessage value)
		{
			return value.CalculateSize();
		}

		public static int ComputeMessageSize(IMessage value)
		{
			int num = value.CalculateSize();
			return ComputeLengthSize(num) + num;
		}

		public static int ComputeBytesSize(ByteString value)
		{
			return ComputeLengthSize(value.Length) + value.Length;
		}

		public static int ComputeUInt32Size(uint value)
		{
			return ComputeRawVarint32Size(value);
		}

		public static int ComputeEnumSize(int value)
		{
			return ComputeInt32Size(value);
		}

		public static int ComputeSFixed32Size(int value)
		{
			return 4;
		}

		public static int ComputeSFixed64Size(long value)
		{
			return 8;
		}

		public static int ComputeSInt32Size(int value)
		{
			return ComputeRawVarint32Size(WritingPrimitives.EncodeZigZag32(value));
		}

		public static int ComputeSInt64Size(long value)
		{
			return ComputeRawVarint64Size(WritingPrimitives.EncodeZigZag64(value));
		}

		public static int ComputeLengthSize(int length)
		{
			return ComputeRawVarint32Size((uint)length);
		}

		public static int ComputeRawVarint32Size(uint value)
		{
			if ((value & 0xFFFFFF80u) == 0)
			{
				return 1;
			}
			if ((value & 0xFFFFC000u) == 0)
			{
				return 2;
			}
			if ((value & 0xFFE00000u) == 0)
			{
				return 3;
			}
			if ((value & 0xF0000000u) == 0)
			{
				return 4;
			}
			return 5;
		}

		public static int ComputeRawVarint64Size(ulong value)
		{
			if ((value & 0xFFFFFFFFFFFFFF80uL) == 0L)
			{
				return 1;
			}
			if ((value & 0xFFFFFFFFFFFFC000uL) == 0L)
			{
				return 2;
			}
			if ((value & 0xFFFFFFFFFFE00000uL) == 0L)
			{
				return 3;
			}
			if ((value & 0xFFFFFFFFF0000000uL) == 0L)
			{
				return 4;
			}
			if ((value & 0xFFFFFFF800000000uL) == 0L)
			{
				return 5;
			}
			if ((value & 0xFFFFFC0000000000uL) == 0L)
			{
				return 6;
			}
			if ((value & 0xFFFE000000000000uL) == 0L)
			{
				return 7;
			}
			if ((value & 0xFF00000000000000uL) == 0L)
			{
				return 8;
			}
			if ((value & 0x8000000000000000uL) == 0L)
			{
				return 9;
			}
			return 10;
		}

		public static int ComputeTagSize(int fieldNumber)
		{
			return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, WireFormat.WireType.Varint));
		}

		public CodedOutputStream(byte[] flatArray)
			: this(flatArray, 0, flatArray.Length)
		{
		}

		private CodedOutputStream(byte[] buffer, int offset, int length)
		{
			output = null;
			this.buffer = ProtoPreconditions.CheckNotNull(buffer, "buffer");
			state.position = offset;
			state.limit = offset + length;
			WriteBufferHelper.Initialize(this, out state.writeBufferHelper);
			leaveOpen = true;
		}

		private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen)
		{
			this.output = ProtoPreconditions.CheckNotNull(output, "output");
			this.buffer = buffer;
			state.position = 0;
			state.limit = buffer.Length;
			WriteBufferHelper.Initialize(this, out state.writeBufferHelper);
			this.leaveOpen = leaveOpen;
		}

		public CodedOutputStream(Stream output)
			: this(output, DefaultBufferSize, leaveOpen: false)
		{
		}

		public CodedOutputStream(Stream output, int bufferSize)
			: this(output, new byte[bufferSize], leaveOpen: false)
		{
		}

		public CodedOutputStream(Stream output, bool leaveOpen)
			: this(output, DefaultBufferSize, leaveOpen)
		{
		}

		public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen)
			: this(output, new byte[bufferSize], leaveOpen)
		{
		}

		public void WriteDouble(double value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteDouble(ref span, ref state, value);
		}

		public void WriteFloat(float value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteFloat(ref span, ref state, value);
		}

		public void WriteUInt64(ulong value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteUInt64(ref span, ref state, value);
		}

		public void WriteInt64(long value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteInt64(ref span, ref state, value);
		}

		public void WriteInt32(int value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteInt32(ref span, ref state, value);
		}

		public void WriteFixed64(ulong value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteFixed64(ref span, ref state, value);
		}

		public void WriteFixed32(uint value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteFixed32(ref span, ref state, value);
		}

		public void WriteBool(bool value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteBool(ref span, ref state, value);
		}

		public void WriteString(string value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteString(ref span, ref state, value);
		}

		public void WriteMessage(IMessage value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WriteContext.Initialize(ref span, ref state, out var ctx);
			try
			{
				WritingPrimitivesMessages.WriteMessage(ref ctx, value);
			}
			finally
			{
				ctx.CopyStateTo(this);
			}
		}

		public void WriteRawMessage(IMessage value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WriteContext.Initialize(ref span, ref state, out var ctx);
			try
			{
				WritingPrimitivesMessages.WriteRawMessage(ref ctx, value);
			}
			finally
			{
				ctx.CopyStateTo(this);
			}
		}

		public void WriteGroup(IMessage value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WriteContext.Initialize(ref span, ref state, out var ctx);
			try
			{
				WritingPrimitivesMessages.WriteGroup(ref ctx, value);
			}
			finally
			{
				ctx.CopyStateTo(this);
			}
		}

		public void WriteBytes(ByteString value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteBytes(ref span, ref state, value);
		}

		public void WriteUInt32(uint value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteUInt32(ref span, ref state, value);
		}

		public void WriteEnum(int value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteEnum(ref span, ref state, value);
		}

		public void WriteSFixed32(int value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteSFixed32(ref span, ref state, value);
		}

		public void WriteSFixed64(long value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteSFixed64(ref span, ref state, value);
		}

		public void WriteSInt32(int value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteSInt32(ref span, ref state, value);
		}

		public void WriteSInt64(long value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteSInt64(ref span, ref state, value);
		}

		public void WriteLength(int length)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteLength(ref span, ref state, length);
		}

		public void WriteTag(int fieldNumber, WireFormat.WireType type)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteTag(ref span, ref state, fieldNumber, type);
		}

		public void WriteTag(uint tag)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteTag(ref span, ref state, tag);
		}

		public void WriteRawTag(byte b1)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawTag(ref span, ref state, b1);
		}

		public void WriteRawTag(byte b1, byte b2)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2);
		}

		public void WriteRawTag(byte b1, byte b2, byte b3)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3);
		}

		public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4);
		}

		public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4, b5);
		}

		internal void WriteRawVarint32(uint value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawVarint32(ref span, ref state, value);
		}

		internal void WriteRawVarint64(ulong value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawVarint64(ref span, ref state, value);
		}

		internal void WriteRawLittleEndian32(uint value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawLittleEndian32(ref span, ref state, value);
		}

		internal void WriteRawLittleEndian64(ulong value)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawLittleEndian64(ref span, ref state, value);
		}

		internal void WriteRawBytes(byte[] value)
		{
			WriteRawBytes(value, 0, value.Length);
		}

		internal void WriteRawBytes(byte[] value, int offset, int length)
		{
			Span<byte> span = new Span<byte>(buffer);
			WritingPrimitives.WriteRawBytes(ref span, ref state, value, offset, length);
		}

		public void Dispose()
		{
			Flush();
			if (!leaveOpen)
			{
				output.Dispose();
			}
		}

		public void Flush()
		{
			Span<byte> span = new Span<byte>(buffer);
			WriteBufferHelper.Flush(ref span, ref state);
		}

		public void CheckNoSpaceLeft()
		{
			WriteBufferHelper.CheckNoSpaceLeft(ref state);
		}
	}
	public abstract class Extension
	{
		internal abstract System.Type TargetType { get; }

		public int FieldNumber { get; }

		internal abstract bool IsRepeated { get; }

		protected Extension(int fieldNumber)
		{
			FieldNumber = fieldNumber;
		}

		internal abstract IExtensionValue CreateValue();
	}
	public sealed class Extension<TTarget, TValue> : Extension where TTarget : IExtendableMessage<TTarget>
	{
		private readonly FieldCodec<TValue> codec;

		internal TValue DefaultValue
		{
			get
			{
				if (codec == null)
				{
					return default(TValue);
				}
				return codec.DefaultValue;
			}
		}

		internal override System.Type TargetType => typeof(TTarget);

		internal override bool IsRepeated => false;

		public Extension(int fieldNumber, FieldCodec<TValue> codec)
			: base(fieldNumber)
		{
			this.codec = codec;
		}

		internal override IExtensionValue CreateValue()
		{
			return new ExtensionValue<TValue>(codec);
		}
	}
	public sealed class RepeatedExtension<TTarget, TValue> : Extension where TTarget : IExtendableMessage<TTarget>
	{
		private readonly FieldCodec<TValue> codec;

		internal override System.Type TargetType => typeof(TTarget);

		internal override bool IsRepeated => true;

		public RepeatedExtension(int fieldNumber, FieldCodec<TValue> codec)
			: base(fieldNumber)
		{
			this.codec = codec;
		}

		internal override IExtensionValue CreateValue()
		{
			return new RepeatedExtensionValue<TValue>(codec);
		}
	}
	public sealed class ExtensionRegistry : ICollection<Extension>, IEnumerable<Extension>, IEnumerable, IDeepCloneable<ExtensionRegistry>
	{
		internal sealed class ExtensionComparer : IEqualityComparer<Extension>
		{
			internal static ExtensionComparer Instance = new ExtensionComparer();

			public bool Equals(Extension a, Extension b)
			{
				return new ObjectIntPair<System.Type>(a.TargetType, a.FieldNumber).Equals(new ObjectIntPair<System.Type>(b.TargetType, b.FieldNumber));
			}

			public int GetHashCode(Extension a)
			{
				return new ObjectIntPair<System.Type>(a.TargetType, a.FieldNumber).GetHashCode();
			}
		}

		private readonly IDictionary<ObjectIntPair<System.Type>, Extension> extensions;

		public int Count => extensions.Count;

		bool ICollection<Extension>.IsReadOnly => false;

		public ExtensionRegistry()
		{
			extensions = new Dictionary<ObjectIntPair<System.Type>, Extension>();
		}

		private ExtensionRegistry(IDictionary<ObjectIntPair<System.Type>, Extension> collection)
		{
			extensions = collection.ToDictionary((KeyValuePair<ObjectIntPair<System.Type>, Extension> k) => k.Key, (KeyValuePair<ObjectIntPair<System.Type>, Extension> v) => v.Value);
		}

		internal bool ContainsInputField(uint lastTag, System.Type target, out Extension extension)
		{
			return extensions.TryGetValue(new ObjectIntPair<System.Type>(target, WireFormat.GetTagFieldNumber(lastTag)), out extension);
		}

		public void Add(Extension extension)
		{
			ProtoPreconditions.CheckNotNull(extension, "extension");
			extensions.Add(new ObjectIntPair<System.Type>(extension.TargetType, extension.FieldNumber), extension);
		}

		public void AddRange(IEnumerable<Extension> extensions)
		{
			ProtoPreconditions.CheckNotNull(extensions, "extensions");
			foreach (Extension extension in extensions)
			{
				Add(extension);
			}
		}

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

		public bool Contains(Extension item)
		{
			ProtoPreconditions.CheckNotNull(item, "item");
			return extensions.ContainsKey(new ObjectIntPair<System.Type>(item.TargetType, item.FieldNumber));
		}

		void ICollection<Extension>.CopyTo(Extension[] array, int arrayIndex)
		{
			ProtoPreconditions.CheckNotNull(array, "array");
			if (arrayIndex < 0 || arrayIndex >= array.Length)
			{
				throw new ArgumentOutOfRangeException("arrayIndex");
			}
			if (array.Length - arrayIndex < Count)
			{
				throw new ArgumentException("The provided array is shorter than the number of elements in the registry");
			}
			foreach (Extension extension in array)
			{
				extensions.Add(new ObjectIntPair<System.Type>(extension.TargetType, extension.FieldNumber), extension);
			}
		}

		public IEnumerator<Extension> GetEnumerator()
		{
			return extensions.Values.GetEnumerator();
		}

		public bool Remove(Extension item)
		{
			ProtoPreconditions.CheckNotNull(item, "item");
			return extensions.Remove(new ObjectIntPair<System.Type>(item.TargetType, item.FieldNumber));
		}

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

		public ExtensionRegistry Clone()
		{
			return new ExtensionRegistry(extensions);
		}
	}
	public static class ExtensionSet
	{
		private static bool TryGetValue<TTarget>(ref ExtensionSet<TTarget> set, Extension extension, out IExtensionValue value) where TTarget : IExtendableMessage<TTarget>
		{
			if (set == null)
			{
				value = null;
				return false;
			}
			return set.ValuesByNumber.TryGetValue(extension.FieldNumber, out value);
		}

		public static TValue Get<TTarget, TValue>(ref ExtensionSet<TTarget> set, Extension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
		{
			if (TryGetValue(ref set, extension, out var value))
			{
				if (value is ExtensionValue<TValue> extensionValue)
				{
					return extensionValue.GetValue();
				}
				object value2 = value.GetValue();
				if (value2 is TValue)
				{
					return (TValue)value2;
				}
				TypeInfo typeInfo = value.GetType().GetTypeInfo();
				if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(ExtensionValue<>))
				{
					System.Type type = typeInfo.GenericTypeArguments[0];
					throw new InvalidOperationException("The stored extension value has a type of '" + type.AssemblyQualifiedName + "'. This a different from the requested type of '" + typeof(TValue).AssemblyQualifiedName + "'.");
				}
				throw new InvalidOperationException("Unexpected extension value type: " + typeInfo.AssemblyQualifiedName);
			}
			return extension.DefaultValue;
		}

		public static RepeatedField<TValue> Get<TTarget, TValue>(ref ExtensionSet<TTarget> set, RepeatedExtension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
		{
			if (TryGetValue(ref set, extension, out var value))
			{
				if (value is RepeatedExtensionValue<TValue> repeatedExtensionValue)
				{
					return repeatedExtensionValue.GetValue();
				}
				TypeInfo typeInfo = value.GetType().GetTypeInfo();
				if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(RepeatedExtensionValue<>))
				{
					System.Type type = typeInfo.GenericTypeArguments[0];
					throw new InvalidOperationException("The stored extension value has a type of '" + type.AssemblyQualifiedName + "'. This a different from the requested type of '" + typeof(TValue).AssemblyQualifiedName + "'.");
				}
				throw new InvalidOperationException("Unexpected extension value type: " + typeInfo.AssemblyQualifiedName);
			}
			return null;
		}

		public static RepeatedField<TValue> GetOrInitialize<TTarget, TValue>(ref ExtensionSet<TTarget> set, RepeatedExtension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
		{
			IExtensionValue value;
			if (set == null)
			{
				value = extension.CreateValue();
				set = new ExtensionSet<TTarget>();
				set.ValuesByNumber.Add(extension.FieldNumber, value);
			}
			else if (!set.ValuesByNumber.TryGetValue(extension.FieldNumber, out value))
			{
				value = extension.CreateValue();
				set.ValuesByNumber.Add(extension.FieldNumber, value);
			}
			return ((RepeatedExtensionValue<TValue>)value).GetValue();
		}

		public static void Set<TTarget, TValue>(ref ExtensionSet<TTarget> set, Extension<TTarget, TValue> extension, TValue value) where TTarget : IExtendableMessage<TTarget>
		{
			ProtoPreconditions.CheckNotNullUnconstrained(value, "value");
			IExtensionValue value2;
			if (set == null)
			{
				value2 = extension.CreateValue();
				set = new ExtensionSet<TTarget>();
				set.ValuesByNumber.Add(extension.FieldNumber, value2);
			}
			else if (!set.ValuesByNumber.TryGetValue(extension.FieldNumber, out value2))
			{
				value2 = extension.CreateValue();
				set.ValuesByNumber.Add(extension.FieldNumber, value2);
			}
			((ExtensionValue<TValue>)value2).SetValue(value);
		}

		public static bool Has<TTarget, TValue>(ref ExtensionSet<TTarget> set, Extension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
		{
			IExtensionValue value;
			return TryGetValue(ref set, extension, out value);
		}

		public static void Clear<TTarget, TValue>(ref ExtensionSet<TTarget> set, Extension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
		{
			if (set != null)
			{
				set.ValuesByNumber.Remove(extension.FieldNumber);
				if (set.ValuesByNumber.Count == 0)
				{
					set = null;
				}
			}
		}

		public static void Clear<TTarget, TValue>(ref ExtensionSet<TTarget> set, RepeatedExtension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
		{
			if (set != null)
			{
				set.ValuesByNumber.Remove(extension.FieldNumber);
				if (set.ValuesByNumber.Count == 0)
				{
					set = null;
				}
			}
		}

		public static bool TryMergeFieldFrom<TTarget>(ref ExtensionSet<TTarget> set, CodedInputStream stream) where TTarget : IExtendableMessage<TTarget>
		{
			ParseContext.Initialize(stream, out var ctx);
			try
			{
				return TryMergeFieldFrom(ref set, ref ctx);
			}
			finally
			{
				ctx.CopyStateTo(stream);
			}
		}

		public static bool TryMergeFieldFrom<TTarget>(ref ExtensionSet<TTarget> set, ref ParseContext ctx) where TTarget : IExtendableMessage<TTarget>
		{
			int tagFieldNumber = WireFormat.GetTagFieldNumber(ctx.LastTag);
			if (set != null && set.ValuesByNumber.TryGetValue(tagFieldNumber, out var value))
			{
				value.MergeFrom(ref ctx);
				return true;
			}
			if (ctx.ExtensionRegistry != null && ctx.ExtensionRegistry.ContainsInputField(ctx.LastTag, typeof(TTarget), out var extension))
			{
				IExtensionValue extensionValue = extension.CreateValue();
				extensionValue.MergeFrom(ref ctx);
				if (set == null)
				{
					set = new ExtensionSet<TTarget>();
				}
				set.ValuesByNumber.Add(extension.FieldNumber, extensionValue);
				return true;
			}
			return false;
		}

		public static void MergeFrom<TTarget>(ref ExtensionSet<TTarget> first, ExtensionSet<TTarget> second) where TTarget : IExtendableMessage<TTarget>
		{
			if (second == null)
			{
				return;
			}
			if (first == null)
			{
				first = new ExtensionSet<TTarget>();
			}
			foreach (KeyValuePair<int, IExtensionValue> item in second.ValuesByNumber)
			{
				if (first.ValuesByNumber.TryGetValue(item.Key, out var value))
				{
					value.MergeFrom(item.Value);
					continue;
				}
				IExtensionValue value2 = item.Value.Clone();
				first.ValuesByNumber[item.Key] = value2;
			}
		}

		public static ExtensionSet<TTarget> Clone<TTarget>(ExtensionSet<TTarget> set) where TTarget : IExtendableMessage<TTarget>
		{
			if (set == null)
			{
				return null;
			}
			ExtensionSet<TTarget> extensionSet = new ExtensionSet<TTarget>();
			foreach (KeyValuePair<int, IExtensionValue> item in set.ValuesByNumber)
			{
				IExtensionValue value = item.Value.Clone();
				extensionSet.ValuesByNumber[item.Key] = value;
			}
			return extensionSet;
		}
	}
	public sealed class ExtensionSet<TTarget> where TTarget : IExtendableMessage<TTarget>
	{
		internal Dictionary<int, IExtensionValue> ValuesByNumber { get; } = new Dictionary<int, IExtensionValue>();

		public override int GetHashCode()
		{
			int num = typeof(TTarget).GetHashCode();
			foreach (KeyValuePair<int, IExtensionValue> item in ValuesByNumber)
			{
				int num2 = item.Key.GetHashCode() ^ item.Value.GetHashCode();
				num ^= num2;
			}
			return num;
		}

		public override bool Equals(object other)
		{
			if (this == other)
			{
				return true;
			}
			ExtensionSet<TTarget> extensionSet = other as ExtensionSet<TTarget>;
			if (ValuesByNumber.Count != extensionSet.ValuesByNumber.Count)
			{
				return false;
			}
			foreach (KeyValuePair<int, IExtensionValue> item in ValuesByNumber)
			{
				if (!extensionSet.ValuesByNumber.TryGetValue(item.Key, out var value))
				{
					return false;
				}
				if (!item.Value.Equals(value))
				{
					return false;
				}
			}
			return true;
		}

		public int CalculateSize()
		{
			int num = 0;
			foreach (IExtensionValue value in ValuesByNumber.Values)
			{
				num += value.CalculateSize();
			}
			return num;
		}

		public void WriteTo(CodedOutputStream stream)
		{
			WriteContext.Initialize(stream, out var ctx);
			try
			{
				WriteTo(ref ctx);
			}
			finally
			{
				ctx.CopyStateTo(stream);
			}
		}

		[SecuritySafeCritical]
		public void WriteTo(ref WriteContext ctx)
		{
			foreach (IExtensionValue value in ValuesByNumber.Values)
			{
				value.WriteTo(ref ctx);
			}
		}

		internal bool IsInitialized()
		{
			return ValuesByNumber.Values.All((IExtensionValue v) => v.IsInitialized());
		}
	}
	internal interface IExtensionValue : IEquatable<IExtensionValue>, IDeepCloneable<IExtensionValue>
	{
		void MergeFrom(ref ParseContext ctx);

		void MergeFrom(IExtensionValue value);

		void WriteTo(ref WriteContext ctx);

		int CalculateSize();

		bool IsInitialized();

		object GetValue();
	}
	internal sealed class ExtensionValue<T> : IExtensionValue, IEquatable<IExtensionValue>, IDeepCloneable<IExtensionValue>
	{
		private T field;

		private readonly FieldCodec<T> codec;

		internal ExtensionValue(FieldCodec<T> codec)
		{
			this.codec = codec;
			field = codec.DefaultValue;
		}

		public int CalculateSize()
		{
			return codec.CalculateUnconditionalSizeWithTag(field);
		}

		public IExtensionValue Clone()
		{
			return new ExtensionValue<T>(codec)
			{
				field = ((field is IDeepCloneable<T>) ? (field as IDeepCloneable<T>).Clone() : field)
			};
		}

		public bool Equals(IExtensionValue other)
		{
			if (this == other)
			{
				return true;
			}
			if (other is ExtensionValue<T> && codec.Equals((other as ExtensionValue<T>).codec))
			{
				return object.Equals(field, (other as ExtensionValue<T>).field);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (17 * 31 + field.GetHashCode()) * 31 + codec.GetHashCode();
		}

		public void MergeFrom(ref ParseContext ctx)
		{
			codec.ValueMerger(ref ctx, ref field);
		}

		public void MergeFrom(IExtensionValue value)
		{
			if (value is ExtensionValue<T>)
			{
				ExtensionValue<T> extensionValue = value as ExtensionValue<T>;
				codec.FieldMerger(ref field, extensionValue.field);
			}
		}

		public void WriteTo(ref WriteContext ctx)
		{
			ctx.WriteTag(codec.Tag);
			codec.ValueWriter(ref ctx, field);
			if (codec.EndTag != 0)
			{
				ctx.WriteTag(codec.EndTag);
			}
		}

		public T GetValue()
		{
			return field;
		}

		object IExtensionValue.GetValue()
		{
			return field;
		}

		public void SetValue(T value)
		{
			field = value;
		}

		public bool IsInitialized()
		{
			if (field is IMessage)
			{
				return (field as IMessage).IsInitialized();
			}
			return true;
		}
	}
	internal sealed class RepeatedExtensionValue<T> : IExtensionValue, IEquatable<IExtensionValue>, IDeepCloneable<IExtensionValue>
	{
		private RepeatedField<T> field;

		private readonly FieldCodec<T> codec;

		internal RepeatedExtensionValue(FieldCodec<T> codec)
		{
			this.codec = codec;
			field = new RepeatedField<T>();
		}

		public int CalculateSize()
		{
			return field.CalculateSize(codec);
		}

		public IExtensionValue Clone()
		{
			return new RepeatedExtensionValue<T>(codec)
			{
				field = field.Clone()
			};
		}

		public bool Equals(IExtensionValue other)
		{
			if (this == other)
			{
				return true;
			}
			if (other is RepeatedExtensionValue<T> && field.Equals((other as RepeatedExtensionValue<T>).field))
			{
				return codec.Equals((other as RepeatedExtensionValue<T>).codec);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (17 * 31 + field.GetHashCode()) * 31 + codec.GetHashCode();
		}

		public void MergeFrom(ref ParseContext ctx)
		{
			field.AddEntriesFrom(ref ctx, codec);
		}

		public void MergeFrom(IExtensionValue value)
		{
			if (value is RepeatedExtensionValue<T>)
			{
				field.Add((value as RepeatedExtensionValue<T>).field);
			}
		}

		public void WriteTo(ref WriteContext ctx)
		{
			field.WriteTo(ref ctx, codec);
		}

		public RepeatedField<T> GetValue()
		{
			return field;
		}

		object IExtensionValue.GetValue()
		{
			return field;
		}

		public bool IsInitialized()
		{
			for (int i = 0; i < field.Count; i++)
			{
				T val = field[i];
				if (!(val is IMessage))
				{
					break;
				}
				if (!(val as IMessage).IsInitialized())
				{
					return false;
				}
			}
			return true;
		}
	}
	public static class FieldCodec
	{
		private static class WrapperCodecs
		{
			private static readonly Dictionary<System.Type, object> Codecs = new Dictionary<System.Type, object>
			{
				{
					typeof(bool),
					ForBool(WireFormat.MakeTag(1, WireFormat.WireType.Varint))
				},
				{
					typeof(int),
					ForInt32(WireFormat.MakeTag(1, WireFormat.WireType.Varint))
				},
				{
					typeof(long),
					ForInt64(WireFormat.MakeTag(1, WireFormat.WireType.Varint))
				},
				{
					typeof(uint),
					ForUInt32(WireFormat.MakeTag(1, WireFormat.WireType.Varint))
				},
				{
					typeof(ulong),
					ForUInt64(WireFormat.MakeTag(1, WireFormat.WireType.Varint))
				},
				{
					typeof(float),
					ForFloat(WireFormat.MakeTag(1, WireFormat.WireType.Fixed32))
				},
				{
					typeof(double),
					ForDouble(WireFormat.MakeTag(1, WireFormat.WireType.Fixed64))
				},
				{
					typeof(string),
					ForString(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited))
				},
				{
					typeof(ByteString),
					ForBytes(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited))
				}
			};

			private static readonly Dictionary<System.Type, object> Readers = new Dictionary<System.Type, object>
			{
				{
					typeof(bool),
					new ValueReader<bool?>(ParsingPrimitivesWrappers.ReadBoolWrapper)
				},
				{
					typeof(int),
					new ValueReader<int?>(ParsingPrimitivesWrappers.ReadInt32Wrapper)
				},
				{
					typeof(long),
					new ValueReader<long?>(ParsingPrimitivesWrappers.ReadInt64Wrapper)
				},
				{
					typeof(uint),
					new ValueReader<uint?>(ParsingPrimitivesWrappers.ReadUInt32Wrapper)
				},
				{
					typeof(ulong),
					new ValueReader<ulong?>(ParsingPrimitivesWrappers.ReadUInt64Wrapper)
				},
				{
					typeof(float),
					BitConverter.IsLittleEndian ? new ValueReader<float?>(ParsingPrimitivesWrappers.ReadFloatWrapperLittleEndian) : new ValueReader<float?>(ParsingPrimitivesWrappers.ReadFloatWrapperSlow)
				},
				{
					typeof(double),
					BitConverter.IsLittleEndian ? new ValueReader<double?>(ParsingPrimitivesWrappers.ReadDoubleWrapperLittleEndian) : new ValueReader<double?>(ParsingPrimitivesWrappers.ReadDoubleWrapperSlow)
				},
				{
					typeof(string),
					null
				},
				{
					typeof(ByteString),
					null
				}
			};

			internal static FieldCodec<T> GetCodec<T>()
			{
				if (!Codecs.TryGetValue(typeof(T), out var value))
				{
					throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T));
				}
				return (FieldCodec<T>)value;
			}

			internal static ValueReader<T?> GetReader<T>() where T : struct
			{
				if (!Readers.TryGetValue(typeof(T), out var value))
				{
					throw new InvalidOperationException("Invalid type argument requested for wrapper reader: " + typeof(T));
				}
				if (value == null)
				{
					FieldCodec<T> nestedCoded = GetCodec<T>();
					return delegate(ref ParseContext ctx)
					{
						return Read(ref ctx, nestedCoded);
					};
				}
				return (ValueReader<T?>)value;
			}

			[SecuritySafeCritical]
			internal static T Read<T>(ref ParseContext ctx, FieldCodec<T> codec)
			{
				int byteLimit = ctx.ReadLength();
				int oldLimit = SegmentedBufferHelper.PushLimit(ref ctx.state, byteLimit);
				T result = codec.DefaultValue;
				uint num;
				while ((num = ctx.ReadTag()) != 0)
				{
					if (num == codec.Tag)
					{
						result = codec.Read(ref ctx);
					}
					else
					{
						ParsingPrimitivesMessages.SkipLastField(ref ctx.buffer, ref ctx.state);
					}
				}
				ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref ctx.state);
				SegmentedBufferHelper.PopLimit(ref ctx.state, oldLimit);
				return result;
			}

			internal static void Write<T>(ref WriteContext ctx, T value, FieldCodec<T> codec)
			{
				ctx.WriteLength(codec.CalculateSizeWithTag(value));
				codec.WriteTagAndValue(ref ctx, value);
			}

			internal static int CalculateSize<T>(T value, FieldCodec<T> codec)
			{
				int num = codec.CalculateSizeWithTag(value);
				return CodedOutputStream.ComputeLengthSize(num) + num;
			}
		}

		public static FieldCodec<string> ForString(uint tag)
		{
			return ForString(tag, "");
		}

		public static FieldCodec<ByteString> ForBytes(uint tag)
		{
			return ForBytes(tag, ByteString.Empty);
		}

		public static FieldCodec<bool> ForBool(uint tag)
		{
			return ForBool(tag, defaultValue: false);
		}

		public static FieldCodec<int> ForInt32(uint tag)
		{
			return ForInt32(tag, 0);
		}

		public static FieldCodec<int> ForSInt32(uint tag)
		{
			return ForSInt32(tag, 0);
		}

		public static FieldCodec<uint> ForFixed32(uint tag)
		{
			return ForFixed32(tag, 0u);
		}

		public static FieldCodec<int> ForSFixed32(uint tag)
		{
			return ForSFixed32(tag, 0);
		}

		public static FieldCodec<uint> ForUInt32(uint tag)
		{
			return ForUInt32(tag, 0u);
		}

		public static FieldCodec<long> ForInt64(uint tag)
		{
			return ForInt64(tag, 0L);
		}

		public static FieldCodec<long> ForSInt64(uint tag)
		{
			return ForSInt64(tag, 0L);
		}

		public static FieldCodec<ulong> ForFixed64(uint tag)
		{
			return ForFixed64(tag, 0uL);
		}

		public static FieldCodec<long> ForSFixed64(uint tag)
		{
			return ForSFixed64(tag, 0L);
		}

		public static FieldCodec<ulong> ForUInt64(uint tag)
		{
			return ForUInt64(tag, 0uL);
		}

		public static FieldCodec<float> ForFloat(uint tag)
		{
			return ForFloat(tag, 0f);
		}

		public static FieldCodec<double> ForDouble(uint tag)
		{
			return ForDouble(tag, 0.0);
		}

		public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
		{
			return ForEnum(tag, toInt32, fromInt32, default(T));
		}

		public static FieldCodec<string> ForString(uint tag, string defaultValue)
		{
			return new FieldCodec<string>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadString();
			}, delegate(ref WriteContext ctx, string value)
			{
				ctx.WriteString(value);
			}, CodedOutputStream.ComputeStringSize, tag, defaultValue);
		}

		public static FieldCodec<ByteString> ForBytes(uint tag, ByteString defaultValue)
		{
			return new FieldCodec<ByteString>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadBytes();
			}, delegate(ref WriteContext ctx, ByteString value)
			{
				ctx.WriteBytes(value);
			}, CodedOutputStream.ComputeBytesSize, tag, defaultValue);
		}

		public static FieldCodec<bool> ForBool(uint tag, bool defaultValue)
		{
			return new FieldCodec<bool>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadBool();
			}, delegate(ref WriteContext ctx, bool value)
			{
				ctx.WriteBool(value);
			}, 1, tag, defaultValue);
		}

		public static FieldCodec<int> ForInt32(uint tag, int defaultValue)
		{
			return new FieldCodec<int>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadInt32();
			}, delegate(ref WriteContext output, int value)
			{
				output.WriteInt32(value);
			}, CodedOutputStream.ComputeInt32Size, tag, defaultValue);
		}

		public static FieldCodec<int> ForSInt32(uint tag, int defaultValue)
		{
			return new FieldCodec<int>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadSInt32();
			}, delegate(ref WriteContext output, int value)
			{
				output.WriteSInt32(value);
			}, CodedOutputStream.ComputeSInt32Size, tag, defaultValue);
		}

		public static FieldCodec<uint> ForFixed32(uint tag, uint defaultValue)
		{
			return new FieldCodec<uint>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadFixed32();
			}, delegate(ref WriteContext output, uint value)
			{
				output.WriteFixed32(value);
			}, 4, tag, defaultValue);
		}

		public static FieldCodec<int> ForSFixed32(uint tag, int defaultValue)
		{
			return new FieldCodec<int>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadSFixed32();
			}, delegate(ref WriteContext output, int value)
			{
				output.WriteSFixed32(value);
			}, 4, tag, defaultValue);
		}

		public static FieldCodec<uint> ForUInt32(uint tag, uint defaultValue)
		{
			return new FieldCodec<uint>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadUInt32();
			}, delegate(ref WriteContext output, uint value)
			{
				output.WriteUInt32(value);
			}, CodedOutputStream.ComputeUInt32Size, tag, defaultValue);
		}

		public static FieldCodec<long> ForInt64(uint tag, long defaultValue)
		{
			return new FieldCodec<long>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadInt64();
			}, delegate(ref WriteContext output, long value)
			{
				output.WriteInt64(value);
			}, CodedOutputStream.ComputeInt64Size, tag, defaultValue);
		}

		public static FieldCodec<long> ForSInt64(uint tag, long defaultValue)
		{
			return new FieldCodec<long>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadSInt64();
			}, delegate(ref WriteContext output, long value)
			{
				output.WriteSInt64(value);
			}, CodedOutputStream.ComputeSInt64Size, tag, defaultValue);
		}

		public static FieldCodec<ulong> ForFixed64(uint tag, ulong defaultValue)
		{
			return new FieldCodec<ulong>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadFixed64();
			}, delegate(ref WriteContext output, ulong value)
			{
				output.WriteFixed64(value);
			}, 8, tag, defaultValue);
		}

		public static FieldCodec<long> ForSFixed64(uint tag, long defaultValue)
		{
			return new FieldCodec<long>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadSFixed64();
			}, delegate(ref WriteContext output, long value)
			{
				output.WriteSFixed64(value);
			}, 8, tag, defaultValue);
		}

		public static FieldCodec<ulong> ForUInt64(uint tag, ulong defaultValue)
		{
			return new FieldCodec<ulong>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadUInt64();
			}, delegate(ref WriteContext output, ulong value)
			{
				output.WriteUInt64(value);
			}, CodedOutputStream.ComputeUInt64Size, tag, defaultValue);
		}

		public static FieldCodec<float> ForFloat(uint tag, float defaultValue)
		{
			return new FieldCodec<float>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadFloat();
			}, delegate(ref WriteContext output, float value)
			{
				output.WriteFloat(value);
			}, 4, tag, defaultValue);
		}

		public static FieldCodec<double> ForDouble(uint tag, double defaultValue)
		{
			return new FieldCodec<double>(delegate(ref ParseContext ctx)
			{
				return ctx.ReadDouble();
			}, delegate(ref WriteContext output, double value)
			{
				output.WriteDouble(value);
			}, 8, tag, defaultValue);
		}

		public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32, T defaultValue)
		{
			return new FieldCodec<T>(delegate(ref ParseContext ctx)
			{
				return fromInt32(ctx.ReadEnum());
			}, delegate(ref WriteContext output, T value)
			{
				output.WriteEnum(toInt32(value));
			}, (T value) => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag, defaultValue);
		}

		public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : class, IMessage<T>
		{
			return new FieldCodec<T>(delegate(ref ParseContext ctx)
			{
				T val = parser.CreateTemplate();
				ctx.ReadMessage(val);
				return val;
			}, delegate(ref WriteContext output, T value)
			{
				output.WriteMessage(value);
			}, delegate(ref ParseContext ctx, ref T v)
			{
				if (v == null)
				{
					v = parser.CreateTemplate();
				}
				ctx.ReadMessage(v);
			}, delegate(ref T v, T v2)
			{
				if (v2 == null)
				{
					return false;
				}
				if (v == null)
				{
					v = v2.Clone();
				}
				else
				{
					v.MergeFrom(v2);
				}
				return true;
			}, (T message) => CodedOutputStream.ComputeMessageSize(message), tag);
		}

		public static FieldCodec<T> ForGroup<T>(uint startTag, uint endTag, MessageParser<T> parser) where T : class, IMessage<T>
		{
			return new FieldCodec<T>(delegate(ref ParseContext ctx)
			{
				T val = parser.CreateTemplate();
				ctx.ReadGroup(val);
				return val;
			}, delegate(ref WriteContext output, T value)
			{
				output.WriteGroup(value);
			}, delegate(ref ParseContext ctx, ref T v)
			{
				if (v == null)
				{
					v = parser.CreateTemplate();
				}
				ctx.ReadGroup(v);
			}, delegate(ref T v, T v2)
			{
				if (v2 == null)
				{
					return v == null;
				}
				if (v == null)
				{
					v = v2.Clone();
				}
				else
				{
					v.MergeFrom(v2);
				}
				return true;
			}, (T message) => CodedOutputStream.ComputeGroupSize(message), startTag, endTag);
		}

		public static FieldCodec<T> ForClassWrapper<T>(uint tag) where T : class
		{
			FieldCodec<T> nestedCodec = WrapperCodecs.GetCodec<T>();
			return new FieldCodec<T>(delegate(ref ParseContext ctx)
			{
				return WrapperCodecs.Read(ref ctx, nestedCodec);
			}, delegate(ref WriteContext output, T value)
			{
				WrapperCodecs.Write(ref output, value, nestedCodec);
			}, delegate(ref ParseContext ctx, ref T v)
			{
				v = WrapperCodecs.Read(ref ctx, nestedCodec);
			}, delegate(ref T v, T v2)
			{
				v = v2;
				return v == null;
			}, (T value) => WrapperCodecs.CalculateSize(value, nestedCodec), tag, 0u, null);
		}

		public static FieldCodec<T?> ForStructWrapper<T>(uint tag) where T : struct
		{
			FieldCodec<T> nestedCodec = WrapperCodecs.GetCodec<T>();
			return new FieldCodec<T?>(WrapperCodecs.GetReader<T>(), delegate(ref WriteContext output, T? value)
			{
				WrapperCodecs.Write(ref output, value.Value, nestedCodec);
			}, delegate(ref ParseContext ctx, ref T? v)
			{
				v = WrapperCodecs.Read(ref ctx, nestedCodec);
			}, delegate(ref T? v, T? v2)
			{
				if (v2.HasValue)
				{
					v = v2;
				}
				return v.HasValue;
			}, (T? value) => value.HasValue ? WrapperCodecs.CalculateSize(value.Value, nestedCodec) : 0, tag, 0u, null);
		}
	}
	internal delegate TValue ValueReader<out TValue>(ref ParseContext ctx);
	internal delegate void ValueWriter<T>(ref WriteContext ctx, T value);
	public sealed class FieldCodec<T>
	{
		internal delegate void InputMerger(ref ParseContext ctx, ref T value);

		internal delegate bool ValuesMerger(ref T value, T other);

		private static readonly EqualityComparer<T> EqualityComparer;

		private static readonly T DefaultDefault;

		private static readonly bool TypeSupportsPacking;

		private readonly int tagSize;

		internal bool PackedRepeatedField { get; }

		internal ValueWriter<T> ValueWriter { get; }

		internal Func<T, int> ValueSizeCalculator { get; }

		internal ValueReader<T> ValueReader { get; }

		internal InputMerger ValueMerger { get; }

		internal ValuesMerger FieldMerger { get; }

		internal int FixedSize { get; }

		internal uint Tag { get; }

		internal uint EndTag { get; }

		internal T DefaultValue { get; }

		static FieldCodec()
		{
			EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<T>();
			TypeSupportsPacking = default(T) != null;
			if (typeof(T) == typeof(string))
			{
				DefaultDefault = (T)(object)"";
			}
			else if (typeof(T) == typeof(ByteString))
			{
				DefaultDefault = (T)(object)ByteString.Empty;
			}
		}

		internal static bool IsPackedRepeatedField(uint tag)
		{
			if (TypeSupportsPacking)
			{
				return WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited;
			}
			return false;
		}

		internal FieldCodec(ValueReader<T> reader, ValueWriter<T> writer, int fixedSize, uint tag, T defaultValue)
			: this(reader, writer, (Func<T, int>)((T _) => fixedSize), tag, defaultValue)
		{
			FixedSize = fixedSize;
		}

		internal FieldCodec(ValueReader<T> reader, ValueWriter<T> writer, Func<T, int> sizeCalculator, uint tag, T defaultValue)
			: this(reader, writer, (InputMerger)delegate(ref ParseContext ctx, ref T v)
			{
				v = reader(ref ctx);
			}, (ValuesMerger)delegate(ref T v, T v2)
			{
				v = v2;
				return true;
			}, sizeCalculator, tag, 0u, defaultValue)
		{
		}

		internal FieldCodec(ValueReader<T> reader, ValueWriter<T> writer, InputMerger inputMerger, ValuesMerger valuesMerger, Func<T, int> sizeCalculator, uint tag, uint endTag = 0u)
			: this(reader, writer, inputMerger, valuesMerger, sizeCalculator, tag, endTag, DefaultDefault)
		{
		}

		internal FieldCodec(ValueReader<T> reader, ValueWriter<T> writer, InputMerger inputMerger, ValuesMerger valuesMerger, Func<T, int> sizeCalculator, uint tag, uint endTag, T defaultValue)
		{
			ValueReader = reader;
			ValueWriter = writer;
			ValueMerger = inputMerger;
			FieldMerger = valuesMerger;
			ValueSizeCalculator = sizeCalculator;
			FixedSize = 0;
			Tag = tag;
			EndTag = endTag;
			DefaultValue = defaultValue;
			tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
			if (endTag != 0)
			{
				tagSize += CodedOutputStream.ComputeRawVarint32Size(endTag);
			}
			PackedRepeatedField = IsPackedRepeatedField(tag);
		}

		public void WriteTagAndValue(CodedOutputStream output, T value)
		{
			WriteContext.Initialize(output, out var ctx);
			try
			{
				WriteTagAndValue(ref ctx, value);
			}
			finally
			{
				ctx.CopyStateTo(output);
			}
		}

		public void WriteTagAndValue(ref WriteContext ctx, T value)
		{
			if (!IsDefault(value))
			{
				ctx.WriteTag(Tag);
				ValueWriter(ref ctx, value);
				if (EndTag != 0)
				{
					ctx.WriteTag(EndTag);
				}
			}
		}

		public T Read(CodedInputStream input)
		{
			ParseContext.Initialize(input, out var ctx);
			try
			{
				return ValueReader(ref ctx);
			}
			finally
			{
				ctx.CopyStateTo(input);
			}
		}

		public T Read(ref ParseContext ctx)
		{
			return ValueReader(ref ctx);
		}

		public int CalculateSizeWithTag(T value)
		{
			if (!IsDefault(value))
			{
				return ValueSizeCalculator(value) + tagSize;
			}
			return 0;
		}

		internal int CalculateUnconditionalSizeWithTag(T value)
		{
			return ValueSizeCalculator(value) + tagSize;
		}

		private bool IsDefault(T value)
		{
			return EqualityComparer.Equals(value, DefaultValue);
		}
	}
	internal sealed class FieldMaskTree
	{
		internal sealed class Node
		{
			public Dictionary<string, Node> Children { get; } = new Dictionary<string, Node>();
		}

		private const char FIELD_PATH_SEPARATOR = '.';

		private readonly Node root = new Node();

		public FieldMaskTree()
		{
		}

		public FieldMaskTree(FieldMask mask)
		{
			MergeFromFieldMask(mask);
		}

		public override string ToString()
		{
			return ToFieldMask().ToString();
		}

		public FieldMaskTree AddFieldPath(string path)
		{
			string[] array = path.Split(new char[1] { '.' });
			if (array.Length == 0)
			{
				return this;
			}
			Node node = root;
			bool flag = false;
			string[] array2 = array;
			foreach (string key in array2)
			{
				if (!flag && node != root && node.Children.Count == 0)
				{
					return this;
				}
				if (!node.Children.TryGetValue(key, out var value))
				{
					flag = true;
					value = new Node();
					node.Children.Add(key, value);
				}
				node = value;
			}
			node.Children.Clear();
			return this;
		}

		public FieldMaskTree MergeFromFieldMask(FieldMask mask)
		{
			foreach (string path in mask.Paths)
			{
				AddFieldPath(path);
			}
			return this;
		}

		public FieldMask ToFieldMask()
		{
			FieldMask fieldMask = new FieldMask();
			if (root.Children.Count != 0)
			{
				List<string> list = new List<string>();
				GetFieldPaths(root, "", list);
				fieldMask.Paths.AddRange(list);
			}
			return fieldMask;
		}

		private void GetFieldPaths(Node node, string path, List<string> paths)
		{
			if (node.Children.Count == 0)
			{
				paths.Add(path);
				return;
			}
			foreach (KeyValuePair<string, Node> child in node.Children)
			{
				string path2 = ((path.Length == 0) ? child.Key : (path + "." + child.Key));
				GetFieldPaths(child.Value, path2, paths);
			}
		}

		public void IntersectFieldPath(string path, FieldMaskTree output)
		{
			if (root.Children.Count == 0)
			{
				return;
			}
			string[] array = path.Split(new char[1] { '.' });
			if (array.Length == 0)
			{
				return;
			}
			Node value = root;
			string[] array2 = array;
			foreach (string key in array2)
			{
				if (value != root && value.Children.Count == 0)
				{
					output.AddFieldPath(path);
					return;
				}
				if (!value.Children.TryGetValue(key, out value))
				{
					return;
				}
			}
			List<string> list = new List<string>();
			GetFieldPaths(value, path, list);
			foreach (string item in list)
			{
				output.AddFieldPath(item);
			}
		}

		public void Merge(IMessage source, IMessage destination, FieldMask.MergeOptions options)
		{
			if (source.Descriptor != destination.Descriptor)
			{
				throw new InvalidProtocolBufferException("Cannot merge messages of different types.");
			}
			if (root.Children.Count != 0)
			{
				Merge(root, "", source, destination, options);
			}
		}

		private void Merge(Node node, string path, IMessage source, IMessage destination, FieldMask.MergeOptions options)
		{
			if (source.Descriptor != destination.Descriptor)
			{
				throw new InvalidProtocolBufferException($"source ({source.Descriptor}) and destination ({destination.Descriptor}) descriptor must be equal");
			}
			MessageDescriptor descriptor = source.Descriptor;
			foreach (KeyValuePair<string, Node> child in node.Children)
			{
				FieldDescriptor fieldDescriptor = descriptor.FindFieldByName(child.Key);
				if (fieldDescriptor == null)
				{
					continue;
				}
				if (child.Value.Children.Count != 0)
				{
					if (fieldDescriptor.IsRepeated || fieldDescriptor.FieldType != FieldType.Message)
					{
						continue;
					}
					object obj = fieldDescriptor.Accessor.GetValue(source);
					object obj2 = fieldDescriptor.Accessor.GetValue(destination);
					if (obj != null || obj2 != null)
					{
						if (obj2 == null)
						{
							obj2 = fieldDescriptor.MessageType.Parser.CreateTemplate();
							fieldDescriptor.Accessor.SetValue(destination, obj2);
						}
						if (obj == null)
						{
							obj = fieldDescriptor.MessageType.Parser.CreateTemplate();
						}
						string path2 = ((path.Length == 0) ? child.Key : (path + "." + child.Key));
						Merge(child.Value, path2, (IMessage)obj, (IMessage)obj2, options);
					}
					continue;
				}
				if (fieldDescriptor.IsRepeated)
				{
					if (options.ReplaceRepeatedFields)
					{
						fieldDescriptor.Accessor.Clear(destination);
					}
					IList obj3 = (IList)fieldDescriptor.Accessor.GetValue(source);
					IList list = (IList)fieldDescriptor.Accessor.GetValue(destination);
					foreach (object item in obj3)
					{
						list.Add(item);
					}
					continue;
				}
				object value = fieldDescriptor.Accessor.GetValue(source);
				if (fieldDescriptor.FieldType == FieldType.Message)
				{
					if (options.ReplaceMessageFields)
					{
						if (value == null)
						{
							fieldDescriptor.Accessor.Clear(destination);
						}
						else
						{
							fieldDescriptor.Accessor.SetValue(destination, value);
						}
					}
					else
					{
						if (value == null)
						{
							continue;
						}
						if (fieldDescriptor.MessageType.IsWrapperType)
						{
							fieldDescriptor.Accessor.SetValue(destination, value);
							continue;
						}
						ByteString data = ((IMessage)value).ToByteString();
						IMessage message = (IMessage)fieldDescriptor.Accessor.GetValue(destination);
						if (message != null)
						{
							message.MergeFrom(data);
						}
						else
						{
							fieldDescriptor.Accessor.SetValue(destination, fieldDescriptor.MessageType.Parser.ParseFrom(data));
						}
					}
				}
				else if (value != null || !options.ReplacePrimitiveFields)
				{
					fieldDescriptor.Accessor.SetValue(destination, value);
				}
				else
				{
					fieldDescriptor.Accessor.Clear(destination);
				}
			}
		}
	}
	internal static class FrameworkPortability
	{
		internal static readonly RegexOptions CompiledRegexWhereAvailable = (System.Enum.IsDefined(typeof(RegexOptions), 8) ? RegexOptions.Compiled : RegexOptions.None);
	}
	public interface IBufferMessage : IMessage
	{
		void InternalMergeFrom(ref ParseContext ctx);

		void InternalWriteTo(ref WriteContext ctx);
	}
	public interface ICustomDiagnosticMessage : IMessage
	{
		string ToDiagnosticString();
	}
	public interface IDeepCloneable<T>
	{
		T Clone();
	}
	public interface IExtendableMessage<T> : IMessage<T>, IMessage, IEquatable<T>, IDeepCloneable<T> where T : IExtendableMessage<T>
	{
		TValue GetExtension<TValue>(Extension<T, TValue> extension);

		RepeatedField<TValue> GetExtension<TValue>(RepeatedExtension<T, TValue> extension);

		RepeatedField<TValue> GetOrInitializeExtension<TValue>(RepeatedExtension<T, TValue> extension);

		void SetExtension<TValue>(Extension<T, TValue> extension, TValue value);

		bool HasExtension<TValue>(Extension<T, TValue> extension);

		void ClearExtension<TValue>(Extension<T, TValue> extension);

		void ClearExtension<TValue>(RepeatedExtension<T, TValue> extension);
	}
	public interface IMessage
	{
		MessageDescriptor Descriptor { get; }

		void MergeFrom(CodedInputStream input);

		void WriteTo(CodedOutputStream output);

		int CalculateSize();
	}
	public interface IMessage<T> : IMessage, IEquatable<T>, IDeepCloneable<T> where T : IMessage<T>
	{
		void MergeFrom(T message);
	}
	public sealed class InvalidJsonException : IOException
	{
		internal InvalidJsonException(string message)
			: base(message)
		{
		}
	}
	public sealed class InvalidProtocolBufferException : IOException
	{
		internal InvalidProtocolBufferException(string message)
			: base(message)
		{
		}

		internal InvalidProtocolBufferException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		internal static InvalidProtocolBufferException MoreDataAvailable()
		{
			return new InvalidProtocolBufferException("Completed reading a message while more data was available in the stream.");
		}

		internal static InvalidProtocolBufferException TruncatedMessage()
		{
			return new InvalidProtocolBufferException("While parsing a protocol message, the input ended unexpectedly in the middle of a field.  This could mean either that the input has been truncated or that an embedded message misreported its own length.");
		}

		internal static InvalidProtocolBufferException NegativeSize()
		{
			return new InvalidProtocolBufferException("CodedInputStream encountered an embedded string or message which claimed to have negative size.");
		}

		internal static InvalidProtocolBufferException MalformedVarint()
		{
			return new InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.");
		}

		internal static InvalidProtocolBufferException InvalidTag()
		{
			return new InvalidProtocolBufferException("Protocol message contained an invalid tag (zero).");
		}

		internal static InvalidProtocolBufferException InvalidWireType()
		{
			return new InvalidProtocolBufferException("Protocol message contained a tag with an invalid wire type.");
		}

		internal static InvalidProtocolBufferException InvalidBase64(Exception innerException)
		{
			return new InvalidProtocolBufferException("Invalid base64 data", innerException);
		}

		internal static InvalidProtocolBufferException InvalidEndTag()
		{
			return new InvalidProtocolBufferException("Protocol message end-group tag did not match expected tag.");
		}

		internal static InvalidProtocolBufferException RecursionLimitExceeded()
		{
			return new InvalidProtocolBufferException("Protocol message had too many levels of nesting.  May be malicious.  Use CodedInputStream.SetRecursionLimit() to increase the depth limit.");
		}

		internal static InvalidProtocolBufferException JsonRecursionLimitExceeded()
		{
			return new InvalidProtocolBufferException("Protocol message had too many levels of nesting.  May be malicious.  Use JsonParser.Settings to increase the depth limit.");
		}

		internal static InvalidProtocolBufferException SizeLimitExceeded()
		{
			return new InvalidProtocolBufferException("Protocol message was too large.  May be malicious.  Use CodedInputStream.SetSizeLimit() to increase the size limit.");
		}

		internal static InvalidProtocolBufferException InvalidMessageStreamTag()
		{
			return new InvalidProtocolBufferException("Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.");
		}

		internal static InvalidProtocolBufferException MissingFields()
		{
			return new InvalidProtocolBufferException("Message was missing required fields");
		}
	}
	public sealed class JsonFormatter
	{
		public sealed class Settings
		{
			public static Settings Default { get; }

			public bool FormatDefaultValues { get; }

			public TypeRegistry TypeRegistry { get; }

			public bool FormatEnumsAsIntegers { get; }

			public bool PreserveProtoFieldNames { get; }

			public string Indentation { get; }

			static Settings()
			{
				Default = new Settings(formatDefaultValues: false);
			}

			public Settings(bool formatDefaultValues)
				: this(formatDefaultValues, TypeRegistry.Empty)
			{
			}

			public Settings(bool formatDefaultValues, TypeRegistry typeRegistry)
				: this(formatDefaultValues, typeRegistry, formatEnumsAsIntegers: false, preserveProtoFieldNames: false)
			{
			}

			private Settings(bool formatDefaultValues, TypeRegistry typeRegistry, bool formatEnumsAsIntegers, bool preserveProtoFieldNames, string indentation = null)
			{
				FormatDefaultValues = formatDefaultValues;
				TypeRegistry = typeRegistry ?? TypeRegistry.Empty;
				FormatEnumsAsIntegers = formatEnumsAsIntegers;
				PreserveProtoFieldNames = preserveProtoFieldNames;
				Indentation = indentation;
			}

			public Settings WithFormatDefaultValues(bool formatDefaultValues)
			{
				return new Settings(formatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
			}

			public Settings WithTypeRegistry(TypeRegistry typeRegistry)
			{
				return new Settings(FormatDefaultValues, typeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
			}

			public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers)
			{
				return new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
			}

			public Settings WithPreserveProtoFieldNames(bool preserveProtoFieldNames)
			{
				return new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, preserveProtoFieldNames, Indentation);
			}

			public Settings WithIndentation(string indentation = "  ")
			{
				return new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, indentation);
			}
		}

		private static class OriginalEnumValueHelper
		{
			private static readonly ConcurrentDictionary<System.Type, Dictionary<object, string>> dictionaries = new ConcurrentDictionary<System.Type, Dictionary<object, string>>();

			[UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "The field for the value must still be present. It will be returned by reflection, will be in this collection, and its name can be resolved.")]
			[UnconditionalSuppressMessage("Trimming", "IL2067", Justification = "The field for the value must still be present. It will be returned by reflection, will be in this collection, and its name can be resolved.")]
			internal static string GetOriginalName(object value)
			{
				dictionaries.GetOrAdd(value.GetType(), (System.Type t) => GetNameMapping(t)).TryGetValue(value, out var value2);
				return value2;
			}

			private static Dictionary<object, string> GetNameMapping([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] System.Type enumType)
			{
				return (from f in enumType.GetTypeInfo().DeclaredFields
					where f.IsStatic
					where f.GetCustomAttributes<OriginalNameAttribute>().FirstOrDefault()?.PreferredAlias ?? true
					select f).ToDictionary((FieldInfo f) => f.GetValue(null), (FieldInfo f) => f.GetCustomAttributes<OriginalNameAttribute>().FirstOrDefault()?.Name ?? f.Name);
			}
		}

		internal const string AnyTypeUrlField = "@type";

		internal const string AnyDiagnosticValueField = "@value";

		internal const string AnyWellKnownTypeValueField = "value";

		private const string NameValueSeparator = ": ";

		private const string ValueSeparator = ", ";

		private const string MultilineValueSeparator = ",";

		private const char ObjectOpenBracket = '{';

		private const char ObjectCloseBracket = '}';

		private const char ListBracketOpen = '[';

		private const char ListBracketClose = ']';

		private static readonly JsonFormatter diagnosticFormatter;

		private static readonly string[] CommonRepresentations;

		private readonly Settings settings;

		private const string Hex = "0123456789abcdef";

		public static JsonFormatter Default { get; }

		private bool DiagnosticOnly => this == diagnosticFormatter;

		static JsonFormatter()
		{
			Default = new JsonFormatter(Settings.Default);
			diagnosticFormatter = new JsonFormatter(Settings.Default);
			CommonRepresentations = new string[160]
			{
				"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t",
				"\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013",
				"\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d",
				"\\u001e", "\\u001f", "", "", "\\\"", "", "", "", "", "",
				"", "", "", "", "", "", "", "", "", "",
				"", "", "", "", "", "", "", "", "", "",
				"\\u003c", "", "\\u003e", "", "", "", "", "", "", "",
				"", "", "", "", "", "", "", "", "", "",
				"", "", "", "", "", "", "", "", "", "",
				"", "", "\\\\", "", "", "", "", "", "", "",
				"", "", "", "", "", "", "", "", "", "",
				"", "", "", "", "", "", "", "", "", "",
				"", "", "", "", "", "", "", "\\u007f", "\\u0080", "\\u0081",
				"\\u0082", "\\u0083", "\\u0084", "\\u0085", "\\u0086", "\\u0087", "\\u0088", "\\u0089", "\\u008a", "\\u008b",
				"\\u008c", "\\u008d", "\\u008e", "\\u008f", "\\u0090", "\\u0091", "\\u0092", "\\u0093", "\\u0094", "\\u0095",
				"\\u0096", "\\u0097", "\\u0098", "\\u0099", "\\u009a", "\\u009b", "\\u009c", "\\u009d", "\\u009e", "\\u009f"
			};
			for (int i = 0; i < CommonRepresentations.Length; i++)
			{
				if (CommonRepresentations[i] == "")
				{
					CommonRepresentations[i] = ((char)i).ToString();
				}
			}
		}

		public JsonFormatter(Settings settings)
		{
			this.settings = ProtoPreconditions.CheckNotNull(settings, "settings");
		}

		public string Format(IMessage message)
		{
			return Format(message, 0);
		}

		public string Format(IMessage message, int indentationLevel)
		{
			StringWriter stringWriter = new StringWriter();
			Format(message, stringWriter, indentationLevel);
			return stringWriter.ToString();
		}

		public void Format(IMessage message, TextWriter writer)
		{
			Format(message, writer, 0);
		}

		public void Format(IMessage message, TextWriter writer, int indentationLevel)
		{
			ProtoPreconditions.CheckNotNull(message, "message");
			ProtoPreconditions.CheckNotNull(writer, "writer");
			if (message.Descriptor.IsWellKnownType)
			{
				WriteWellKnownTypeValue(writer, message.Descriptor, message, indentationLevel);
			}
			else
			{
				WriteMessage(writer, message, indentationLevel);
			}
		}

		public static string ToDiagnosticString(IMessage message)
		{
			ProtoPreconditions.CheckNotNull(message, "message");
			return diagnosticFormatter.Format(message);
		}

		private void WriteMessage(TextWriter writer, IMessage message, int indentationLevel)
		{
			if (message == null)
			{
				WriteNull(writer);
				return;
			}
			if (DiagnosticOnly && message is ICustomDiagnosticMessage customDiagnosticMessage)
			{
				writer.Write(customDiagnosticMessage.ToDiagnosticString());
				return;
			}
			WriteBracketOpen(writer, '{');
			bool hasFields = WriteMessageFields(writer, message, assumeFirstFieldWritten: false, indentationLevel + 1);
			WriteBracketClose(writer, '}', hasFields, indentationLevel);
		}

		private bool WriteMessageFields(TextWriter writer, IMessage message, bool assumeFirstFieldWritten, int indentationLevel)
		{
			MessageDescriptor.FieldCollection fields = message.Descriptor.Fields;
			bool flag = !assumeFirstFieldWritten;
			foreach (FieldDescriptor item in fields.InFieldNumberOrder())
			{
				IFieldAccessor accessor = item.Accessor;
				object value = accessor.GetValue(message);
				if (ShouldFormatFieldValue(message, item, value))
				{
					MaybeWriteValueSeparator(writer, flag);
					MaybeWriteValueWhitespace(writer, indentationLevel);
					if (settings.PreserveProtoFieldNames)
					{
						WriteString(writer, accessor.Descriptor.Name);
					}
					else
					{
						WriteString(writer, accessor.Descriptor.JsonName);
					}
					writer.Write(": ");
					WriteValue(writer, value, indentationLevel);
					flag = false;
				}
			}
			return !flag;
		}

		private void MaybeWriteValueSeparator(TextWriter writer, bool first)
		{
			if (!first)
			{
				writer.Write((settings.Indentation == null) ? ", " : ",");
			}
		}

		private bool ShouldFormatFieldValue(IMessage message, FieldDescriptor field, object value)
		{
			if (!field.HasPresence)
			{
				if (!settings.FormatDefaultValues)
				{
					return !IsDefaultValue(field, value);
				}
				return true;
			}
			return field.Accessor.HasValue(message);
		}

		internal static string ToJsonName(string name)
		{
			StringBuilder stringBuilder = new StringBuilder(name.Length);
			bool flag = false;
			foreach (char c in name)
			{
				if (c == '_')
				{
					flag = true;
				}
				else if (flag)
				{
					stringBuilder.Append(char.ToUpperInvariant(c));
					flag = false;
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		internal static string FromJsonName(string name)
		{
			StringBuilder stringBuilder = new StringBuilder(name.Length);
			foreach (char c in name)
			{
				if (char.IsUpper(c))
				{
					stringBuilder.Append('_');
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static void WriteNull(TextWriter writer)
		{
			writer.Write("null");
		}

		private static bool IsDefaultValue(FieldDescriptor descriptor, object value)
		{
			if (descriptor.IsMap)
			{
				return ((IDictionary)value).Count == 0;
			}
			if (descriptor.IsRepeated)
			{
				return ((IList)value).Count == 0;
			}
			switch (descriptor.FieldType)
			{
			case FieldType.Bool:
				return !(bool)value;
			case FieldType.Bytes:
				return (ByteString)value == ByteString.Empty;
			case FieldType.String:
				return (string)value == "";
			case FieldType.Double:
				return (double)value == 0.0;
			case FieldType.Int32:
			case FieldType.SFixed32:
			case FieldType.SInt32:
			case FieldType.Enum:
				return (int)value == 0;
			case FieldType.Fixed32:
			case FieldType.UInt32:
				return (uint)value == 0;
			case FieldType.UInt64:
			case FieldType.Fixed64:
				return (ulong)value == 0;
			case FieldType.Int64:
			case FieldType.SFixed64:
			case FieldType.SInt64:
				return (long)value == 0;
			case FieldType.Float:
				return (float)value == 0f;
			case FieldType.Group:
			case FieldType.Message:
				return value == null;
			default:
				throw new ArgumentException("Invalid field type");
			}
		}

		public void WriteValue(TextWriter writer, object value)
		{
			WriteValue(writer, value, 0);
		}

		public void WriteValue(TextWriter writer, object value, int indentationLevel)
		{
			if (value == null || value is NullValue)
			{
				WriteNull(writer);
			}
			else if (value is bool flag)
			{
				writer.Write(flag ? "true" : "false");
			}
			else if (value is ByteString byteString)
			{
				writer.Write('"');
				writer.Write(byteString.ToBase64());
				writer.Write('"');
			}
			else if (value is string text)
			{
				WriteString(writer, text);
			}
			else if (value is IDictionary dictionary)
			{
				WriteDictionary(writer, dictionary, indentationLevel);
			}
			else if (value is IList list)
			{
				WriteList(writer, list, indentationLevel);
			}
			else if (value is int || value is uint)
			{
				IFormattable formattable = (IFormattable)value;
				writer.Write(formattable.ToString("d", CultureInfo.InvariantCulture));
			}
			else if (value is long || value is ulong)
			{
				writer.Write('"');
				IFormattable formattable2 = (IFormattable)value;
				writer.Write(formattable2.ToString("d", CultureInfo.InvariantCulture));
				writer.Write('"');
			}
			else if (value is System.Enum)
			{
				if (settings.FormatEnumsAsIntegers)
				{
					WriteValue(writer, (int)value);
					return;
				}
				string originalName = OriginalEnumValueHelper.GetOriginalName(value);
				if (originalName != null)
				{
					WriteString(writer, originalName);
				}
				else
				{
					WriteValue(writer, (int)value);
				}
			}
			else if (value is float || value is double)
			{
				string text2 = ((IFormattable)value).ToString("r", CultureInfo.InvariantCulture);
				switch (text2)
				{
				case "NaN":
				case "Infinity":
				case "-Infinity":
					writer.Write('"');
					writer.Write(text2);
					writer.Write('"');
					break;
				default:
					writer.Write(text2);
					break;
				}
			}
			else
			{
				if (!(value is IMessage message))
				{
					throw new ArgumentException("Unable to format value of type " + value.GetType());
				}
				Format(message, writer, indentationLevel);
			}
		}

		private void WriteWellKnownTypeValue(TextWriter writer, MessageDescriptor descriptor, object value, int indentationLevel)
		{
			if (value == null)
			{
				WriteNull(writer);
			}
			else if (descriptor.IsWrapperType)
			{
				if (value is IMessage message)
				{
					value = message.Descriptor.Fields[1].Accessor.GetValue(message);
				}
				WriteValue(writer, value);
			}
			else if (descriptor.FullName == Timestamp.Descriptor.FullName)
			{
				WriteTimestamp(writer, (IMessage)value);
			}
			else if (descriptor.FullName == Duration.Descriptor.FullName)
			{
				WriteDuration(writer, (IMessage)value);
			}
			else if (descriptor.FullName == FieldMask.Descriptor.FullName)
			{
				WriteFieldMask(writer, (IMessage)value);
			}
			else if (descriptor.FullName == Struct.Descriptor.FullName)
			{
				WriteStruct(writer, (IMessage)value, indentationLevel);
			}
			else if (descriptor.FullName == ListValue.Descriptor.FullName)
			{
				IFieldAccessor accessor = descriptor.Fields[1].Accessor;
				WriteList(writer, (IList)accessor.GetValue((IMessage)value), indentationLevel);
			}
			else if (descriptor.FullName == Value.Descriptor.FullName)
			{
				WriteStructFieldValue(writer, (IMessage)value, indentationLevel);
			}
			else if (descriptor.FullName == Any.Descriptor.FullName)
			{
				WriteAny(writer, (IMessage)value, indentationLevel);
			}
			else
			{
				WriteMessage(writer, (IMessage)value, indentationLevel);
			}
		}

		private void WriteTimestamp(TextWriter writer, IMessage value)
		{
			int nanoseconds = (int)value.Descriptor.Fields[2].Accessor.GetValue(value);
			long seconds = (long)value.Descriptor.Fields[1].Accessor.GetValue(value);
			writer.Write(Timestamp.ToJson(seconds, nanoseconds, DiagnosticOnly));
		}

		private void WriteDuration(TextWriter writer, IMessage value)
		{
			int nanoseconds = (int)value.Descriptor.Fields[2].Accessor.GetValue(value);
			long seconds = (long)value.Descriptor.Fields[1].Accessor.GetValue(value);
			writer.Write(Duration.ToJson(seconds, nanoseconds, DiagnosticOnly));
		}

		private void WriteFieldMask(TextWriter writer, IMessage value)
		{
			IList<string> paths = (IList<string>)value.Descriptor.Fields[1].Accessor.GetValue(value);
			writer.Write(FieldMask.ToJson(paths, DiagnosticOnly));
		}

		private void WriteAny(TextWriter writer, IMessage value, int indentationLevel)
		{
			if (DiagnosticOnly)
			{
				WriteDiagnosticOnlyAny(writer, value);
				return;
			}
			string text = (string)value.Descriptor.Fields[1].Accessor.GetValue(value);
			ByteString data = (ByteString)value.Descriptor.Fields[2].Accessor.GetValue(value);
			string typeName = Any.GetTypeName(text);
			MessageDescriptor messageDescriptor = settings.TypeRegistry.Find(typeName);
			if (messageDescriptor == null)
			{
				throw new InvalidOperationException("Type registry has no descriptor for type name '" + typeName + "'");
			}
			IMessage message = messageDescriptor.Parser.ParseFrom(data);
			WriteBracketOpen(writer, '{');
			WriteString(writer, "@type");
			writer.Write(": ");
			WriteString(writer, text);
			if (messageDescriptor.IsWellKnownType)
			{
				writer.Write(", ");
				WriteString(writer, "value");
				writer.Write(": ");
				WriteWellKnownTypeValue(writer, messageDescriptor, message, indentationLevel);
			}
			else
			{
				WriteMessageFields(writer, message, assumeFirstFieldWritten: true, indentationLevel);
			}
			WriteBracketClose(writer, '}', hasFields: true, indentationLevel);
		}

		private void WriteDiagnosticOnlyAny(TextWriter writer, IMessage value)
		{
			string text = (string)value.Descriptor.Fields[1].Accessor.GetValue(value);
			ByteString byteString = (ByteString)value.Descriptor.Fields[2].Accessor.GetValue(value);
			writer.Write("{ ");
			WriteString(writer, "@type");
			writer.Write(": ");
			WriteString(writer, text);
			writer.Write(", ");
			WriteString(writer, "@value");
			writer.Write(": ");
			writer.Write('"');
			writer.Write(byteString.ToBase64());
			writer.Write('"');
			writer.Write(" }");
		}

		private void WriteStruct(TextWriter writer, IMessage message, int indentationLevel)
		{
			WriteBracketOpen(writer, '{');
			IDictionary obj = (IDictionary)message.Descriptor.Fields[1].Accessor.GetValue(message);
			bool flag = true;
			foreach (DictionaryEntry item in obj)
			{
				string text = (string)item.Key;
				IMessage message2 = (IMessage)item.Value;
				if (string.IsNullOrEmpty(text) || message2 == null)
				{
					throw new InvalidOperationException("Struct fields cannot have an empty key or a null value.");
				}
				MaybeWriteValueSeparator(writer, flag);
				MaybeWriteValueWhitespace(writer, indentationLevel + 1);
				WriteString(writer, text);
				writer.Write(": ");
				WriteStructFieldValue(writer, message2, indentationLevel + 1);
				flag = false;
			}
			WriteBracketClose(writer, '}', !flag, indentationLevel);
		}

		private void WriteStructFieldValue(TextWriter writer, IMessage message, int indentationLevel)
		{
			FieldDescriptor caseFieldDescriptor = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message);
			if (caseFieldDescriptor == null)
			{
				throw new InvalidOperationException("Value message must contain a value for the oneof.");
			}
			object value = caseFieldDescriptor.Accessor.GetValue(message);
			switch (caseFieldDescriptor.FieldNumber)
			{
			case 2:
			case 3:
			case 4:
				WriteValue(writer, value);
				break;
			case 5:
			case 6:
			{
				IMessage message2 = (IMessage)caseFieldDescriptor.Accessor.GetValue(message);
				WriteWellKnownTypeValue(writer, message2.Descriptor, message2, indentationLevel);
				break;
			}
			case 1:
				WriteNull(writer);
				break;
			default:
				throw new InvalidOperationException("Unexpected case in struct field: " + caseFieldDescriptor.FieldNumber);
			}
		}

		internal void WriteList(TextWriter writer, IList list, int indentationLevel = 0)
		{
			WriteBracketOpen(writer, '[');
			bool flag = true;
			foreach (object item in list)
			{
				MaybeWriteValueSeparator(writer, flag);
				MaybeWriteValueWhitespace(writer, indentationLevel + 1);
				WriteValue(writer, item, indentationLevel + 1);
				flag = false;
			}
			WriteBracketClose(writer, ']', !flag, indentationLevel);
		}

		internal void WriteDictionary(TextWriter writer, IDictionary dictionary, int indentationLevel = 0)
		{
			WriteBracketOpen(writer, '{');
			bool flag = true;
			foreach (DictionaryEntry item in dictionary)
			{
				string text2;
				if (item.Key is string text)
				{
					text2 = text;
				}
				else
				{
					object key = item.Key;
					if (key is bool)
					{
						text2 = (((bool)key) ? "true" : "false");
					}
					else
					{
						if (!(item.Key is int) && !(item.Key is uint) && !(item.Key is long) && !(item.Key is ulong))
						{
							if (item.Key == null)
							{
								throw new ArgumentException("Dictionary has entry with null key");
							}
							throw new ArgumentException("Unhandled dictionary key type: " + item.Key.GetType());
						}
						text2 = ((IFormattable)item.Key).ToString("d", CultureInfo.InvariantCulture);
					}
				}
				MaybeWriteValueSeparator(writer, flag);
				MaybeWriteValueWhitespace(writer, indentationLevel + 1);
				WriteString(writer, text2);
				writer.Write(": ");
				WriteValue(writer, item.Value, indentationLevel + 1);
				flag = false;
			}
			WriteBracketClose(writer, '}', !flag, indentationLevel);
		}

		internal static void WriteString(TextWriter writer, string text)
		{
			writer.Write('"');
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (c < '\u00a0')
				{
					writer.Write(CommonRepresentations[(uint)c]);
					continue;
				}
				if (char.IsHighSurrogate(c))
				{
					i++;
					if (i == text.Length || !char.IsLowSurrogate(text[i]))
					{
						throw new ArgumentException("String contains low surrogate not followed by high surrogate");
					}
					HexEncodeUtf16CodeUnit(writer, c);
					HexEncodeUtf16CodeUnit(writer, text[i]);
					continue;
				}
				if (char.IsLowSurrogate(c))
				{
					throw new ArgumentException("String contains high surrogate not preceded by low surrogate");
				}
				switch (c)
				{
				case 173u:
				case 1757u:
				case 1807u:
				case 6068u:
				case 6069u:
				case 65279u:
				case 65529u:
				case 65530u:
				case 65531u:
					HexEncodeUtf16CodeUnit(writer, c);
					continue;
				}
				if ((c >= '\u0600' && c <= '\u0603') || (c >= '\u200b' && c <= '\u200f') || (c >= '\u2028' && c <= '\u202e') || (c >= '\u2060' && c <= '\u2064') || (c >= '\u206a' && c <= '\u206f'))
				{
					HexEncodeUtf16CodeUnit(writer, c);
				}
				else
				{
					writer.Write(c);
				}
			}
			writer.Write('"');
		}

		private static void HexEncodeUtf16CodeUnit(TextWriter writer, char c)
		{
			writer.Write("\\u");
			writer.Write("0123456789abcdef"[((int)c >> 12) & 0xF]);
			writer.Write("0123456789abcdef"[((int)c >> 8) & 0xF]);
			writer.Write("0123456789abcdef"[((int)c >> 4) & 0xF]);
			writer.Write("0123456789abcdef"[c & 0xF]);
		}

		private void WriteBracketOpen(TextWriter writer, char openChar)
		{
			writer.Write(openChar);
			if (settings.Indentation == null)
			{
				writer.Write(' ');
			}
		}

		private void WriteBracketClose(TextWriter writer, char closeChar, bool hasFields, int indentationLevel)
		{
			if (hasFields)
			{
				if (settings.Indentation != null)
				{
					writer.WriteLine();
					WriteIndentation(writer, indentationLevel);
				}
				else
				{
					writer.Write(" ");
				}
			}
			writer.Write(closeChar);
		}

		private void MaybeWriteValueWhitespace(TextWriter writer, int indentationLevel)
		{
			if (settings.Indentation != null)
			{
				writer.WriteLine();
				WriteIndentation(writer, indentationLevel);
			}
		}

		private void WriteIndentation(TextWriter writer, int indentationLevel)
		{
			for (int i = 0; i < indentationLevel; i++)
			{
				writer.Write(settings.Indentation);
			}
		}
	}
	public sealed class JsonParser
	{
		public sealed class Settings
		{
			public static Settings Default { get; }

			public int RecursionLimit { get; }

			public TypeRegistry TypeRegistry { get; }

			public bool IgnoreUnknownFields { get; }

			static Settings()
			{
				Default = new Settings(100);
			}

			private Settings(int recursionLimit, TypeRegistry typeRegistry, bool ignoreUnknownFields)
			{
				RecursionLimit = recursionLimit;
				TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, "typeRegistry");
				IgnoreUnknownFields = ignoreUnknownFields;
			}

			public Settings(int recursionLimit)
				: this(recursionLimit, TypeRegistry.Empty)
			{
			}

			public Settings(int recursionLimit, TypeRegistry typeRegistry)
				: this(recursionLimit, typeRegistry, ignoreUnknownFields: false)
			{
			}

			public Settings WithIgnoreUnknownFields(bool ignoreUnknownFields)
			{
				return new Settings(RecursionLimit, TypeRegistry, ignoreUnknownFields);
			}

			public Settings WithRecursionLimit(int recursionLimit)
			{
				return new Settings(recursionLimit, TypeRegistry, IgnoreUnknownFields);
			}

			public Settings WithTypeRegistry(TypeRegistry typeRegistry)
			{
				return new Settings(RecursionLimit, ProtoPreconditions.CheckNotNull(typeRegistry, "typeRegistry"), IgnoreUnknownFields);
			}
		}

		private static readonly Regex TimestampRegex = new Regex("^(?<datetime>[0-9]{4}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9])(?<subseconds>\\.[0-9]{1,9})?(?<offset>(Z|[+-][0-1][0-9]:[0-5][0-9]))$", FrameworkPortability.CompiledRegexWhereAvailable);

		private static readonly Regex DurationRegex = new Regex("^(?<sign>-)?(?<int>[0-9]{1,12})(?<subseconds>\\.[0-9]{1,9})?s$", FrameworkPortability.CompiledRegexWhereAvailable);

		private static readonly int[] SubsecondScalingFactors = new int[11]
		{
			0, 100000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10,
			1
		};

		private static readonly char[] FieldMaskPathSeparators = new char[1] { ',' };

		private static readonly EnumDescriptor NullValueDescriptor = StructReflection.Descriptor.EnumTypes.Single((EnumDescriptor ed) => ed.ClrType == typeof(NullValue));

		private static readonly JsonParser defaultInstance = new JsonParser(Settings.Default);

		private static readonly Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>> WellKnownTypeHandlers = new Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
		{
			{
				Timestamp.Descriptor.FullName,
				delegate(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
				{
					MergeTimestamp(message, tokenizer.Next());
				}
			},
			{
				Duration.Descriptor.FullName,
				delegate(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
				{
					MergeDuration(message, tokenizer.Next());
				}
			},
			{
				Value.Descriptor.FullName,
				delegate(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
				{
					parser.MergeStructValue(message, tokenizer);
				}
			},
			{
				ListValue.Descriptor.FullName,
				delegate(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
				{
					parser.MergeRepeatedField(message, message.Descriptor.Fields[1], tokenizer);
				}
			},
			{
				Struct.Descriptor.FullName,
				delegate(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
				{
					parser.MergeStruct(message, tokenizer);
				}
			},
			{
				Any.Descriptor.FullName,
				delegate(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
				{
					parser.MergeAny(message, tokenizer);
				}
			},
			{
				FieldMask.Descriptor.FullName,
				delegate(JsonParser parser, IMessage message, JsonTokenizer tokenizer)
				{
					MergeFieldMask(message, tokenizer.Next());
				}
			},
			{
				Int32Value.Descriptor.FullName,
				MergeWrapperField
			},
			{
				Int64Value.Descriptor.FullName,
				MergeWrapperField
			},
			{
				UInt32Value.Descriptor.FullName,
				MergeWrapperField
			},
			{
				UInt64Value.Descriptor.FullName,
				MergeWrapperField
			},
			{
				FloatValue.Descriptor.FullName,
				MergeWrapperFi