Decompiled source of CookieFx v0.1.0

CookieFx.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using CookieFx.Client;
using CookieFx.Network;
using CookieFx.Network.Payloads;
using CookieFx.Patches;
using CookieFx.Platform;
using CookieFx.Players;
using CookieFx.Server;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CookieSylvia")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("CookieFx")]
[assembly: AssemblyTitle("CookieFx")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CookieFx
{
	internal static class Ensure
	{
		public static Guid ServerId(string path)
		{
			Guard.NotNullOrWhiteSpace(path, "path");
			Directory.CreateDirectory(path);
			path = Path.Combine(path, ".ServerId");
			try
			{
				using StreamReader streamReader = File.OpenText(path);
				if (Guid.TryParse(streamReader.ReadLine(), out var result))
				{
					Logger.Info($"Loaded existing ServerId [{result:D}] from the current save file.");
					return result;
				}
				Logger.Error("ServerId in current save is corrupt and will be reassigned - clients will no longer recognize us.");
			}
			catch (FileNotFoundException)
			{
			}
			Guid guid = Guid.NewGuid();
			Logger.Info($"Assigning new ServerId [{guid:D}] to current save file.");
			using StreamWriter streamWriter = File.CreateText(path);
			streamWriter.Write(guid.ToString("D"));
			return guid;
		}
	}
	[DebuggerStepThrough]
	public static class Guard
	{
		[DebuggerStepThrough]
		internal static class Throws
		{
			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentNull(string? paramName)
			{
				throw new ArgumentNullException(paramName, "Parameter " + paramName + " must be not null.");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentNullable(string? paramName)
			{
				throw new ArgumentException(paramName, "Type parameter " + paramName + " must not be nullable.");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentEmptyGuid(string? paramName)
			{
				throw new ArgumentException("Parameter " + paramName + " must not be an empty Guid.", paramName);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentNullOrEmpty(string? value, string? paramName)
			{
				if (value == null)
				{
					throw new ArgumentNullException(paramName, "Parameter " + paramName + " must be not null.");
				}
				throw new ArgumentException("Parameter " + paramName + " must not be empty.", paramName);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentNullOrWhiteSpace(string? value, string? paramName)
			{
				if (value == null)
				{
					throw new ArgumentNullException(paramName, "Parameter " + paramName + " must be not null.");
				}
				throw new ArgumentException("Parameter " + paramName + " must not be empty or whitespace.", paramName);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeLessThan<T>(T value, T max, string? paramName)
			{
				throw new ArgumentOutOfRangeException(paramName, $"Parameter {paramName} ({typeof(T)}) must be less than {max}, was {value}");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeLessThanOrEqualTo<T>(T value, T max, string? paramName)
			{
				throw new ArgumentOutOfRangeException(paramName, $"Parameter {paramName} ({typeof(T)}) must be less than or equal to {max}, was {value}");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeGreaterThan<T>(T value, T min, string? paramName)
			{
				throw new ArgumentOutOfRangeException(paramName, $"Parameter {paramName} ({typeof(T)}) must be greater than {min}, was {value}");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeGreaterThanOrEqualTo<T>(T value, T min, string? paramName)
			{
				throw new ArgumentOutOfRangeException(paramName, $"Parameter {paramName} ({typeof(T)}) must be greater than or equal to {min}, was {value}");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeBetween<T>(T value, T min, T max, string? paramName)
			{
				throw new ArgumentOutOfRangeException(paramName, $"Parameter {paramName} ({typeof(T)}) must be between {min} and {max}, was {value}");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeBetweenOrEqualTo<T>(T value, T min, T max, string? paramName)
			{
				throw new ArgumentOutOfRangeException(paramName, $"Parameter {paramName} ({typeof(T)}) must be between or equal to {min} and {max}, was {value}");
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeTrue(string? message, string? paramName)
			{
				if (message == null)
				{
					throw new ArgumentException("Paramter " + paramName + " must be true.", paramName);
				}
				throw new ArgumentException(message, paramName);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			[DoesNotReturn]
			public static void ArgumentMustBeFalse(string? message, string? paramName)
			{
				if (message == null)
				{
					throw new ArgumentException("Paramter " + paramName + " must be false.", paramName);
				}
				throw new ArgumentException(message, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotEmpty(Guid value, [CallerArgumentExpression("value")] string? paramName = null)
		{
			if (value == Guid.Empty)
			{
				Throws.ArgumentEmptyGuid(paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotNull<T>([NotNull] T? value, [CallerArgumentExpression("value")] string? paramName = null) where T : class
		{
			if (value == null)
			{
				Throws.ArgumentNull(paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotNull<T>([NotNull] T? value, [CallerArgumentExpression("value")] string? paramName = null) where T : struct
		{
			if (!value.HasValue)
			{
				Throws.ArgumentNull(paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotNullAny<T>([NotNull] T? value, [CallerArgumentExpression("value")] string? paramName = null)
		{
			if (value == null)
			{
				Throws.ArgumentNull(paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotNullable<T>()
		{
			if ((object)Nullable.GetUnderlyingType(typeof(T)) != null)
			{
				Throws.ArgumentNullable(typeof(T).Name);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotNullable(Type type)
		{
			if ((object)Nullable.GetUnderlyingType(type) != null)
			{
				Throws.ArgumentNullable(type.Name);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotNullOrEmpty(string? value, [CallerArgumentExpression("value")] string? paramName = null)
		{
			if (string.IsNullOrEmpty(value))
			{
				Throws.ArgumentNullOrEmpty(value, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NotNullOrWhiteSpace(string? value, [CallerArgumentExpression("value")] string? paramName = null)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				Throws.ArgumentNullOrWhiteSpace(value, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void MustBeLessThan<T>(T value, T max, [CallerArgumentExpression("value")] string? paramName = null) where T : IComparable<T>
		{
			if (value.CompareTo(max) >= 0)
			{
				Throws.ArgumentMustBeLessThan(value, max, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void MustBeLessThanOrEqualTo<T>(T value, T max, [CallerArgumentExpression("value")] string? paramName = null) where T : IComparable<T>
		{
			if (value.CompareTo(max) > 0)
			{
				Throws.ArgumentMustBeLessThanOrEqualTo(value, max, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void MustBeGreaterThan<T>(T value, T min, [CallerArgumentExpression("value")] string? paramName = null) where T : IComparable<T>
		{
			if (value.CompareTo(min) <= 0)
			{
				Throws.ArgumentMustBeGreaterThan(value, min, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void MustBeGreaterThanOrEqualTo<T>(T value, T min, [CallerArgumentExpression("value")] string? paramName = null) where T : IComparable<T>
		{
			if (value.CompareTo(min) < 0)
			{
				Throws.ArgumentMustBeGreaterThanOrEqualTo(value, min, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void MustBeBetween<T>(T value, T min, T max, [CallerArgumentExpression("value")] string? paramName = null) where T : IComparable<T>
		{
			if (value.CompareTo(min) <= 0 || value.CompareTo(max) >= 0)
			{
				Throws.ArgumentMustBeBetween(value, min, max, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void MustBeBetweenOrEqualTo<T>(T value, T min, T max, [CallerArgumentExpression("value")] string? paramName = null) where T : IComparable<T>
		{
			if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
			{
				Throws.ArgumentMustBeBetweenOrEqualTo(value, min, max, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void IsTrue([DoesNotReturnIf(false)] bool condition, string? message = null, [CallerArgumentExpression("condition")] string? paramName = null)
		{
			if (!condition)
			{
				Throws.ArgumentMustBeTrue(message, paramName);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void IsFalse([DoesNotReturnIf(true)] bool condition, string? message = null, [CallerArgumentExpression("condition")] string? paramName = null)
		{
			if (condition)
			{
				Throws.ArgumentMustBeFalse(message, paramName);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("CookieFx", "CookieFx", "0.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			Logger.Source = new BepInLoggerSource(((BaseUnityPlugin)this).Logger);
			Harmony val = new Harmony("CookieFx");
			val.PatchAll(typeof(Plugin).Assembly);
			try
			{
				MethodInfo methodInfo = AccessTools.Method("DeleteFileButton_BetterSaves:DeleteFile", (Type[])null, (Type[])null);
				if ((object)methodInfo != null)
				{
					MethodInfo methodInfo2 = AccessUtils.MethodInfo((Expression<Func<Func<IEnumerable<CodeInstruction>, IEnumerable<CodeInstruction>>>>)(() => SavePatches.DeleteFileBetterSaves));
					val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null);
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Compat] LCBetterSaves: Patched");
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[Compat] LCBetterSaves: Not found");
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"[Compat] LCBetterSaves: Failed\n{arg}");
			}
			FuckThisShitPatches.PatchTheirStuff(val);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"CookieFx v0.1.0 loaded.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Icon by Kaede");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Save Path: " + Application.persistentDataPath));
		}
	}
	public static class Reflect
	{
		public static IEnumerable<Assembly> AllAssemblies()
		{
			return from assembly in AppDomain.CurrentDomain.GetAssemblies()
				where !assembly.FullName.StartsWith("Microsoft.VisualStudio")
				select assembly;
		}

		public static IEnumerable<Type> AllTypes()
		{
			return AllAssemblies().SelectMany((Assembly assembly) => assembly.AllTypes());
		}

		public static IEnumerable<Type> AllTypesAssignableTo(Type baseType)
		{
			Type baseType2 = baseType;
			return AllAssemblies().SelectMany((Assembly assembly) => assembly.AllTypesAssignableTo(baseType2));
		}

		public static IEnumerable<Type> AllTypes(this Assembly assembly)
		{
			try
			{
				return assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				Logger.Warning($"[Reflect] AllTypes in {assembly}: {ex.Message}\n{ex.StackTrace}");
				return ex.Types.Where((Type type) => (object)type != null);
			}
		}

		public static IEnumerable<Type> AllTypesAssignableTo(this Assembly assembly, Type baseType)
		{
			Type baseType2 = baseType;
			Assembly assembly2 = assembly;
			return assembly2.AllTypes().Where(delegate(Type type)
			{
				try
				{
					return baseType2.IsAssignableFrom(type);
				}
				catch (TypeLoadException ex)
				{
					Logger.Warning($"[Reflect] AllTypesAssignableTo in {assembly2}: {ex.Message}\n{ex.StackTrace}");
					return false;
				}
			});
		}
	}
	internal static class PluginInfo
	{
		public const string Guid = "CookieFx";

		public const string Name = "CookieFx";

		public const string Version = "0.1.0";
	}
}
namespace CookieFx.Server
{
	public abstract class AbstractServer
	{
		public Guid ServerId { get; }

		public Networking Networking { get; }

		public abstract bool IsIntegrated { get; }

		public bool IsStopping { get; protected set; }

		public abstract ServerPlayer? Host { get; }

		public IEnumerable<ServerPlayer> Players => PlayerManager.Players;

		public abstract AbstractPlayerManager PlayerManager { get; }

		protected AbstractServer(Networking networking)
		{
			Guard.NotNull(networking, "networking");
			Networking = networking;
			string serverSavePath = SaveUtils.ServerSavePath;
			ServerId = Ensure.ServerId(serverSavePath);
			Logger.Info("Starting server...");
		}

		protected AbstractServer(Networking networking, Guid guid)
		{
			Guard.NotNull(networking, "networking");
			Guard.NotEmpty(guid, "guid");
			ServerId = guid;
			Networking = networking;
			Logger.Info("Starting server...");
		}

		public virtual void Save()
		{
			foreach (ServerPlayer player in Players)
			{
				if (player.CanPersist)
				{
					player.OnSave(SaveUtils.ServerSavePath);
				}
				else
				{
					Logger.Error($"Failed to save {player} since they can't be persisted.");
				}
			}
		}

		public virtual void Stop()
		{
			IsStopping = true;
			PlayerUtils.Disconnect("Stopping Server");
		}

		protected internal virtual void OnShutdown()
		{
			IsStopping = true;
			Logger.Info("Server is stopping...");
			foreach (ServerPlayer player in PlayerManager.Players)
			{
				PluginUtils.OnPlayerUntracked(player);
				player.DetachAll();
			}
			PlayerManager.Clear();
		}
	}
	public sealed class DedicatedServer : AbstractServer
	{
		public override bool IsIntegrated => false;

		public override ServerPlayer? Host => null;

		public DedicatedPlayerManager DedicatedPlayerManager { get; }

		public override AbstractPlayerManager PlayerManager => DedicatedPlayerManager;

		private DedicatedServer(Networking networking)
			: base(networking)
		{
			DedicatedPlayerManager = new DedicatedPlayerManager(this);
		}

		internal static DedicatedServer StartServer(Networking networking)
		{
			return new DedicatedServer(networking);
		}
	}
	public sealed class IntegratedServer : AbstractServer
	{
		public override bool IsIntegrated => true;

		public GameClient Client { get; }

		public override ServerPlayer? Host => IntegratedPlayerManager.Host;

		public IntegratedPlayerManager IntegratedPlayerManager { get; }

		public override AbstractPlayerManager PlayerManager => IntegratedPlayerManager;

		internal IntegratedServer(Networking networking, GameClient client)
			: base(networking)
		{
			Guard.NotNull(client, "client");
			Client = client;
			IntegratedPlayerManager = new IntegratedPlayerManager(this, client);
		}
	}
}
namespace CookieFx.Players
{
	public abstract class AbstractClientPlayer : AbstractPlayer
	{
		public sealed override bool IsClient => true;

		public abstract bool IsLocal { get; }

		public override string CurrentSavePath => SaveUtils.ClientSavePath;
	}
	public abstract class AbstractPlayer
	{
		private readonly Dictionary<Type, IPlayerComponent> _components = new Dictionary<Type, IPlayerComponent>();

		private readonly Dictionary<Type, string> _componentPaths = new Dictionary<Type, string>();

		public abstract bool IsClient { get; }

		public abstract ulong NetworkId { get; }

		public abstract bool CanPersist { get; }

		public abstract ulong PersistentId { get; }

		public abstract string CurrentSavePath { get; }

		public IEnumerable<Type> ComponentTypes => _components.Keys;

		public IEnumerable<IPlayerComponent> Components => _components.Values;

		public bool TryAttach<T>(T component, out T? previous) where T : class, IPlayerComponent
		{
			if (TryAttach(typeof(T), component, out IPlayerComponent previous2))
			{
				previous = (T)previous2;
				return true;
			}
			previous = null;
			return false;
		}

		public bool TryAttach<T>(T component) where T : class, IPlayerComponent
		{
			return TryAttach(typeof(T), component);
		}

		public T? Attach<T>(T component) where T : class, IPlayerComponent
		{
			return (T)Attach(typeof(T), component);
		}

		public T? GetOrNull<T>() where T : class, IPlayerComponent
		{
			return (T)GetOrNull(typeof(T));
		}

		[return: NotNullIfNotNull("value")]
		public T? GetOrDefault<T>(T? value = null) where T : class, IPlayerComponent
		{
			return (T)GetOrDefault(typeof(T), value);
		}

		public T Get<T>() where T : class, IPlayerComponent
		{
			return (T)Get(typeof(T));
		}

		public bool TryGet<T>([NotNullWhen(true)] out T? value) where T : class, IPlayerComponent
		{
			if (TryGet(typeof(T), out IPlayerComponent value2))
			{
				value = (T)value2;
				return true;
			}
			value = null;
			return false;
		}

		public bool TryDetach<T>([NotNullWhen(true)] out T? component) where T : class, IPlayerComponent
		{
			if (TryDetach(typeof(T), out IPlayerComponent component2))
			{
				component = (T)component2;
				return true;
			}
			component = null;
			return false;
		}

		public bool TryDetach<T>() where T : class, IPlayerComponent
		{
			return TryDetach(typeof(T));
		}

		public T? Detach<T>() where T : class, IPlayerComponent
		{
			return (T)Detach(typeof(T));
		}

		public bool TryAttach(Type type, IPlayerComponent component, out IPlayerComponent? previous)
		{
			Guard.NotNull(type, "type");
			Guard.IsFalse(type.IsValueType, null, "type.IsValueType");
			Guard.NotNull(component, "component");
			Guard.IsTrue(type.IsAssignableFrom(component.GetType()), null, "type.IsAssignableFrom(component.GetType())");
			if (!PluginUtils.TryGetPluginId(type.Assembly, out string pluginId))
			{
				throw new InvalidOperationException("Cannot find a plugin for the assembly [" + type.Assembly.FullName + "]");
			}
			if (_components.TryGetValue(type, out previous))
			{
				OnSaveComponent(type, previous, CurrentSavePath);
			}
			string text = pluginId + "-" + component.ComponentId;
			OnLoadComponent(type, component, CurrentSavePath, text);
			if (!AboutToAttach(component))
			{
				return false;
			}
			if (previous != null && !AboutToDetach(previous))
			{
				previous = null;
				return false;
			}
			_components[type] = component;
			_componentPaths[type] = text;
			return true;
		}

		public bool TryAttach(Type type, IPlayerComponent component)
		{
			Guard.NotNull(type, "type");
			Guard.IsFalse(type.IsValueType, null, "type.IsValueType");
			Guard.NotNull(component, "component");
			Guard.IsTrue(type.IsAssignableFrom(component.GetType()), null, "type.IsAssignableFrom(component.GetType())");
			if (!PluginUtils.TryGetPluginId(type.Assembly, out string pluginId))
			{
				throw new InvalidOperationException("Cannot find a plugin for the assembly [" + type.Assembly.FullName + "]");
			}
			if (_components.TryGetValue(type, out IPlayerComponent value))
			{
				OnSaveComponent(type, value, CurrentSavePath);
			}
			string text = pluginId + "-" + component.ComponentId;
			OnLoadComponent(type, component, CurrentSavePath, text);
			if (!AboutToAttach(component))
			{
				return false;
			}
			if (value != null && !AboutToDetach(value))
			{
				return false;
			}
			_components[type] = component;
			_componentPaths[type] = text;
			return true;
		}

		public IPlayerComponent? Attach(Type type, IPlayerComponent component)
		{
			Guard.NotNull(type, "type");
			Guard.IsFalse(type.IsValueType, null, "type.IsValueType");
			Guard.NotNull(component, "component");
			Guard.IsTrue(type.IsAssignableFrom(component.GetType()), null, "type.IsAssignableFrom(component.GetType())");
			if (!PluginUtils.TryGetPluginId(type.Assembly, out string pluginId))
			{
				throw new InvalidOperationException("Cannot find a plugin for the assembly [" + type.Assembly.FullName + "]");
			}
			if (_components.TryGetValue(type, out IPlayerComponent value))
			{
				OnSaveComponent(type, value, CurrentSavePath);
			}
			string text = pluginId + "-" + component.ComponentId;
			OnLoadComponent(type, component, CurrentSavePath, text);
			if (!AboutToAttach(component))
			{
				throw new InvalidOperationException("Cannot attach component [" + type.Name + "] since the component doesn't want to be attached.");
			}
			if (value != null && !AboutToDetach(value))
			{
				throw new InvalidOperationException("Cannot replace component [" + type.Name + "] since the existing component doesn't want to be detached.");
			}
			_components[type] = component;
			_componentPaths[type] = text;
			return value;
		}

		public IPlayerComponent? GetOrNull(Type type)
		{
			Guard.NotNull(type, "type");
			Guard.IsFalse(type.IsValueType, null, "type.IsValueType");
			IPlayerComponent value;
			return _components.TryGetValue(type, out value) ? value : null;
		}

		[return: NotNullIfNotNull("value")]
		public IPlayerComponent? GetOrDefault(Type type, IPlayerComponent? value = null)
		{
			return GetOrNull(type) ?? value;
		}

		public IPlayerComponent Get(Type type)
		{
			return GetOrNull(type) ?? throw new InvalidOperationException("Player doesn't have a [" + type.Name + "] component.");
		}

		public bool TryGet(Type type, [NotNullWhen(true)] out IPlayerComponent? value)
		{
			value = GetOrNull(type);
			return value != null;
		}

		public bool TryDetach(Type type, [NotNullWhen(true)] out IPlayerComponent? component)
		{
			Guard.NotNull(type, "type");
			Guard.IsFalse(type.IsValueType, null, "type.IsValueType");
			if (_components.TryGetValue(type, out component))
			{
				OnSaveComponent(type, component, CurrentSavePath);
				if (AboutToDetach(component))
				{
					_components.Remove(type);
					_componentPaths.Remove(type);
					return true;
				}
			}
			component = null;
			return false;
		}

		public bool TryDetach(Type type)
		{
			Guard.NotNull(type, "type");
			Guard.IsFalse(type.IsValueType, null, "type.IsValueType");
			if (_components.TryGetValue(type, out IPlayerComponent value))
			{
				OnSaveComponent(type, value, CurrentSavePath);
				if (AboutToDetach(value))
				{
					_components.Remove(type);
					_componentPaths.Remove(type);
					return true;
				}
			}
			return false;
		}

		public IPlayerComponent? Detach(Type type)
		{
			Guard.NotNull(type, "type");
			Guard.IsFalse(type.IsValueType, null, "type.IsValueType");
			if (_components.TryGetValue(type, out IPlayerComponent value))
			{
				OnSaveComponent(type, value, CurrentSavePath);
				if (AboutToDetach(value))
				{
					_components.Remove(type);
					_componentPaths.Remove(type);
					return value;
				}
			}
			throw new InvalidOperationException("Cannot detach component [" + type.Name + "] since the component isn't attached.");
		}

		internal void DetachAll(bool save = true)
		{
			foreach (var (type2, playerComponent2) in _components)
			{
				if (save && CanPersist)
				{
					OnSaveComponent(type2, playerComponent2, CurrentSavePath);
				}
				try
				{
					playerComponent2.OnPlayerDetach(this, forced: true);
				}
				catch (Exception ex)
				{
					Logger.Error("Component [" + playerComponent2.ComponentId + "] threw an exception during [Forced Detach]. " + ex.Message + "\n" + ex.StackTrace);
				}
			}
			_components.Clear();
		}

		private bool AboutToAttach(IPlayerComponent component)
		{
			try
			{
				return component.OnPlayerAttach(this);
			}
			catch (Exception ex)
			{
				Logger.Error("Component [" + component.ComponentId + "] threw an exception during [Attach]. " + ex.Message + "\n" + ex.StackTrace);
				return false;
			}
		}

		private bool AboutToDetach(IPlayerComponent component)
		{
			try
			{
				return component.OnPlayerDetach(this, forced: false);
			}
			catch (Exception ex)
			{
				Logger.Error("Component [" + component.ComponentId + "] threw an exception during [Detach]. " + ex.Message + "\n" + ex.StackTrace);
				return true;
			}
		}

		protected internal void OnSave(string save)
		{
			foreach (var (type2, component) in _components)
			{
				OnSaveComponent(type2, component, save);
			}
		}

		protected internal void OnLoad(string save)
		{
			foreach (var (type2, component) in _components)
			{
				OnLoadComponent(type2, component, save, null);
			}
		}

		protected virtual void OnSaveComponent(Type type, IPlayerComponent component, string save)
		{
			Guard.NotNull(type, "type");
			Guard.NotNull(component, "component");
			Guard.NotNullOrWhiteSpace(save, "save");
			if (!component.ShouldPersist(this))
			{
				return;
			}
			if (!CanPersist)
			{
				throw new InvalidOperationException($"Tried to save [{_componentPaths[type]}] for {this} but the player cannot be persisted.");
			}
			string componentSavePath = GetComponentSavePath(type, save, null);
			try
			{
				Directory.CreateDirectory(componentSavePath);
				component.OnPlayerSave(this, componentSavePath);
			}
			catch (Exception ex)
			{
				Logger.Error("Component [" + component.ComponentId + "] threw an exception during [Save]. " + ex.Message + "\n" + ex.StackTrace);
			}
		}

		protected virtual void OnLoadComponent(Type type, IPlayerComponent component, string save, string? componentPath)
		{
			Guard.NotNull(type, "type");
			Guard.NotNull(component, "component");
			Guard.NotNullOrWhiteSpace(save, "save");
			if (!component.ShouldPersist(this))
			{
				return;
			}
			if (!CanPersist)
			{
				throw new InvalidOperationException($"Tried to load [{componentPath ?? _componentPaths[type]}] for {this} but the player cannot be persisted.");
			}
			string componentSavePath = GetComponentSavePath(type, save, componentPath);
			if (Directory.Exists(componentSavePath))
			{
				try
				{
					component.OnPlayerLoad(this, componentSavePath);
					return;
				}
				catch (Exception ex)
				{
					Logger.Error("Component [" + component.ComponentId + "] threw an exception during [Load]. " + ex.Message + "\n" + ex.StackTrace);
					return;
				}
			}
			try
			{
				Directory.CreateDirectory(componentSavePath);
				component.OnPlayerDefaults(this, componentSavePath);
			}
			catch (Exception ex2)
			{
				Logger.Error("Component [" + component.ComponentId + "] threw an exception during [Defaults]. " + ex2.Message + "\n" + ex2.StackTrace);
			}
		}

		private string GetComponentSavePath(Type type, string save, string? component)
		{
			if (!CanPersist)
			{
				throw new InvalidOperationException($"Tried to find save path for component [{type.FullName}] but the player {this} cannot be persisted.");
			}
			string path = component ?? _componentPaths[type];
			return Path.Combine(save, "Players", PersistentId.ToString(), path);
		}

		public abstract void Disconnect(string? reason);

		public abstract override string ToString();
	}
	public sealed class ClientPlayer : AbstractClientPlayer
	{
		public override bool IsLocal => true;

		public override ulong NetworkId => Client.NetworkId;

		public override bool CanPersist => PersistentId != 0;

		public override ulong PersistentId { get; }

		public GameClient Client { get; }

		public NetworkSession.Server ServerSession { get; }

		internal ClientPlayer(Networking networking, GameClient client, NetworkSession.Server session)
		{
			Guard.NotNull(networking, "networking");
			Guard.NotNull(client, "client");
			Guard.NotNull(session, "session");
			Client = client;
			ServerSession = session;
			PersistentId = session.PersistentId;
		}

		public override void Disconnect(string? reason = null)
		{
			ServerSession.Disconnect(reason);
		}

		public override string ToString()
		{
			return $"ClientPlayer(net:{NetworkId}, persist:{PersistentId})";
		}
	}
	public interface IPlayerComponent
	{
		string ComponentId => GetType().FullName;

		bool ShouldPersist(AbstractPlayer player)
		{
			return true;
		}

		bool OnPlayerAttach(AbstractPlayer player)
		{
			return true;
		}

		bool OnPlayerDetach(AbstractPlayer player, bool forced)
		{
			return true;
		}

		void OnPlayerDefaults(AbstractPlayer player, string path)
		{
		}

		void OnPlayerSave(AbstractPlayer player, string path)
		{
		}

		void OnPlayerLoad(AbstractPlayer player, string path)
		{
		}
	}
	public sealed class OtherClientPlayer : AbstractClientPlayer
	{
		public override bool IsLocal => false;

		public override ulong NetworkId { get; }

		public override bool CanPersist => PersistentId != 0;

		public override ulong PersistentId { get; }

		internal OtherClientPlayer(ulong networkId, ulong persistentId)
		{
			NetworkId = networkId;
			PersistentId = persistentId;
		}

		public override void Disconnect(string? reason)
		{
			PlayerUtils.Disconnect(NetworkId, reason);
			if (reason == null)
			{
				Logger.Info($"Kicked {NetworkId}");
			}
			else
			{
				Logger.Info($"Kicked {NetworkId} because: {reason}");
			}
		}

		public override string ToString()
		{
			return $"OtherClientPlayer(net:{NetworkId}, persist:{PersistentId})";
		}
	}
	public sealed class ServerPlayer : AbstractPlayer
	{
		public override bool IsClient => false;

		public override ulong NetworkId => Session.NetworkId;

		public override bool CanPersist => PersistentId != 0;

		public override ulong PersistentId { get; }

		public override string CurrentSavePath => SaveUtils.ServerSavePath;

		public AbstractServer Server { get; }

		public NetworkSession.Client Session { get; }

		internal ServerPlayer(AbstractServer server, NetworkSession.Client session)
		{
			Guard.NotNull(server, "server");
			Guard.NotNull(session, "session");
			Server = server;
			Session = session;
			if (!PlayerUtils.TryGetPersistentId(session.NetworkId, out var persistentId))
			{
				Disconnect("Unable to find your PersistentId");
			}
			else
			{
				PersistentId = persistentId;
			}
		}

		public override void Disconnect(string? reason)
		{
			Session.Disconnect(reason);
		}

		public override string ToString()
		{
			return $"ServerPlayer(net:{NetworkId}, persist:{PersistentId})";
		}
	}
	public abstract class AbstractPlayerManager
	{
		protected readonly Dictionary<ulong, ServerPlayer> _players = new Dictionary<ulong, ServerPlayer>();

		protected readonly Dictionary<ulong, NetworkSession.Client> _tracked = new Dictionary<ulong, NetworkSession.Client>();

		public AbstractServer Server { get; }

		public IEnumerable<ServerPlayer> Players => _players.Values;

		public IEnumerable<NetworkSession.Client> Sessions => _tracked.Values;

		protected AbstractPlayerManager(AbstractServer server)
		{
			Guard.NotNull(server, "server");
			Server = server;
			Logger.Info("ServerPlayerManager setup");
		}

		public IEnumerable<ServerPlayer> PlayersExcept(ulong networkId)
		{
			return _players.Values.Where((ServerPlayer p) => p.NetworkId != networkId);
		}

		public IEnumerable<ServerPlayer> PlayersExcept(params ulong[] networkIds)
		{
			ulong[] networkIds2 = networkIds;
			Guard.NotNull(networkIds2, "networkIds");
			return _players.Values.Where((ServerPlayer p) => Array.IndexOf(networkIds2, p.NetworkId) == -1);
		}

		public virtual bool TryGetPlayer(ulong networkId, [NotNullWhen(true)] out ServerPlayer? player)
		{
			return _players.TryGetValue(networkId, out player);
		}

		public virtual bool TryGetSession(ulong networkId, [NotNullWhen(true)] out NetworkSession.Client? session)
		{
			return _tracked.TryGetValue(networkId, out session);
		}

		protected internal virtual void OnClientAdded(ulong networkId)
		{
			if (Server.IsStopping)
			{
				Logger.Warning($"Client {networkId} tried to connect while we're stopping.");
				return;
			}
			Networking networking = Server.Networking;
			Logger.Info($"Started tracking {networkId}");
			if (_tracked.TryGetValue(networkId, out NetworkSession.Client value))
			{
				Logger.Error($"{networkId} is already being tracked.");
				value.Disconnect("You are already tracked.");
				return;
			}
			value = NetworkSession.CreateClient(networking, networkId);
			_tracked.Add(networkId, value);
			((MonoBehaviour)networking.Backend).StartCoroutine(SetupTimeout(networkId));
			value.StartSetup(Server.Networking);
		}

		protected internal virtual void OnClientRemoved(ulong networkId)
		{
			if (!Server.IsStopping)
			{
				Logger.Info($"Stopped tracking {networkId}");
				if (!_tracked.TryGetValue(networkId, out NetworkSession.Client value))
				{
					Logger.Error($"{networkId} was already not tracked.");
				}
				else if (_players.ContainsKey(networkId))
				{
					OnClientDisconnect(value);
				}
			}
		}

		protected internal virtual IEnumerator SetupTimeout(ulong networkId)
		{
			Stopwatch timer = Stopwatch.StartNew();
			yield return (object)new WaitUntil((Func<bool>)(() => Server.IsStopping || timer.Elapsed.TotalSeconds > 80.0 || !_tracked.ContainsKey(networkId) || _players.ContainsKey(networkId)));
			timer.Stop();
			if (!Server.IsStopping && !_players.ContainsKey(networkId) && _tracked.TryGetValue(networkId, out NetworkSession.Client session) && timer.Elapsed.TotalSeconds > 60.0)
			{
				session.Disconnect("Setup timed out. (Server-side)");
			}
		}

		protected internal virtual void OnClientConnected(NetworkSession.Client session)
		{
			Guard.NotNull(session, "session");
			ulong networkId = session.NetworkId;
			Logger.Info($"Player connected: {networkId}");
			if (_players.TryGetValue(networkId, out ServerPlayer value))
			{
				Logger.Error($"Player {networkId} is already in player list.");
				value.Disconnect("You are already connected.");
				return;
			}
			value = new ServerPlayer(Server, session);
			_players.Add(networkId, value);
			PluginUtils.OnPlayerTracked(value);
			Server.Networking.SendPlayerTracking(this, value, track: true);
			Server.Networking.InvokePlayerConnected(value);
		}

		protected internal virtual void OnClientDisconnect(NetworkSession.Client session)
		{
			Guard.NotNull(session, "session");
			ulong networkId = session.NetworkId;
			Logger.Info($"Player disconnected: {networkId}");
			if (!_players.TryGetValue(networkId, out ServerPlayer value))
			{
				Logger.Error($"Player {networkId} was not found in player list.");
				return;
			}
			Server.Networking.InvokePlayerDisconnected(value);
			PluginUtils.OnPlayerUntracked(value);
			Server.Networking.SendPlayerTracking(this, value, track: false);
			value.DetachAll();
			_players.Remove(networkId);
		}

		internal void Clear()
		{
			_players.Clear();
			_tracked.Clear();
		}
	}
	public sealed class DedicatedPlayerManager : AbstractPlayerManager
	{
		public new DedicatedServer Server { get; }

		public DedicatedPlayerManager(DedicatedServer server)
			: base(server)
		{
			Server = server;
		}
	}
	public sealed class IntegratedPlayerManager : AbstractPlayerManager
	{
		public new IntegratedServer Server { get; }

		public GameClient Client { get; }

		public NetworkSession.Client HostSession { get; }

		public ServerPlayer? Host { get; }

		public IntegratedPlayerManager(IntegratedServer server, GameClient client)
			: base(server)
		{
			Guard.NotNull(client, "client");
			Server = server;
			Client = client;
			HostSession = NetworkSession.CreateClient(server.Networking, client.NetworkId);
		}

		protected internal override void OnClientAdded(ulong networkId)
		{
			if (networkId == HostSession.NetworkId)
			{
				((MonoBehaviour)Server.Networking.Backend).StartCoroutine(DelayedHostConnect());
			}
			else
			{
				base.OnClientAdded(networkId);
			}
		}

		private IEnumerator DelayedHostConnect()
		{
			Logger.Info("Delaying host player.");
			yield return (object)new WaitUntil((Func<bool>)(() => PlayerUtils.CanPersistLocal || Client.IsStopping || Server.IsStopping));
			if (!Client.IsStopping && !Server.IsStopping)
			{
				Logger.Info("Continuing delayed host player.");
				OnClientConnected(HostSession);
			}
			else
			{
				Logger.Warning("Host player interrupted.");
			}
		}

		protected internal override void OnClientRemoved(ulong networkId)
		{
			if (networkId == HostSession.NetworkId)
			{
				OnClientDisconnect(HostSession);
			}
			else
			{
				base.OnClientRemoved(networkId);
			}
		}

		protected internal override void OnClientConnected(NetworkSession.Client session)
		{
			Guard.NotNull(session, "session");
			if (session == HostSession)
			{
				ulong networkId = session.NetworkId;
				Logger.Info($"Local Player connected: {networkId}");
				if (_players.TryGetValue(networkId, out ServerPlayer value))
				{
					Logger.Error($"Local Player {networkId} is already in player list.");
					value.Disconnect("You are already connected.");
					return;
				}
				session.StartSetup(Server.Networking);
				value = new ServerPlayer(Server, HostSession);
				_players.Add(networkId, value);
				PluginUtils.OnPlayerTracked(value);
				Server.Networking.SendPlayerTracking(this, value, track: true);
				Server.Networking.InvokePlayerConnected(value);
			}
			else
			{
				base.OnClientConnected(session);
			}
		}
	}
}
namespace CookieFx.Platform
{
	public static class AccessUtils
	{
		private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;

		private const BindingFlags AllDeclared = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;

		public static MethodInfo? ImplementedMethod(Type implementation, Type type, string name, Type[]? parameters = null)
		{
			if ((object)implementation == null)
			{
				Logger.Warning("AccessUtils ImplementedMethod: implementation is null.");
				return null;
			}
			if ((object)type == null)
			{
				Logger.Warning("AccessUtils ImplementedMethod: type is null.");
				return null;
			}
			if (!type.IsAssignableFrom(implementation))
			{
				Logger.Warning($"AccessUtils ImplementedMethod: {implementation} is not assignable to {type}.");
				return null;
			}
			MethodInfo methodInfo = ((parameters != null) ? type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty, null, parameters, Array.Empty<ParameterModifier>()) : type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty));
			if ((object)methodInfo == null)
			{
				Logger.Warning($"AccessUtils ImplementedMethod: Could not find method for type {type} and name {name} and parameters {((parameters != null) ? GeneralExtensions.Description(parameters) : null)}.");
				return null;
			}
			InterfaceMapping interfaceMap = implementation.GetInterfaceMap(type);
			MethodInfo[] interfaceMethods = interfaceMap.InterfaceMethods;
			for (int i = 0; i < interfaceMap.InterfaceMethods.Length; i++)
			{
				if (interfaceMethods[i].Equals(methodInfo))
				{
					return interfaceMap.TargetMethods[i];
				}
			}
			Logger.Warning($"AccessUtils ImplementedMethod: Implementation for {methodInfo} not found in {implementation}.");
			return null;
		}

		public static MethodInfo? ImplementedMethod(Type implementation, MethodInfo method)
		{
			if ((object)implementation == null)
			{
				Logger.Warning("AccessUtils ImplementedMethod: implementation is null.");
				return null;
			}
			if ((object)method == null)
			{
				Logger.Warning("AccessUtils ImplementedMethod: method is null.");
				return null;
			}
			Type declaringType = method.DeclaringType;
			if (!declaringType.IsAssignableFrom(implementation))
			{
				Logger.Warning($"AccessUtils ImplementedMethod: {implementation} is not assignable to {declaringType}.");
				return null;
			}
			InterfaceMapping interfaceMap = implementation.GetInterfaceMap(declaringType);
			MethodInfo[] interfaceMethods = interfaceMap.InterfaceMethods;
			for (int i = 0; i < interfaceMap.InterfaceMethods.Length; i++)
			{
				if (interfaceMethods[i].Equals(method))
				{
					return interfaceMap.TargetMethods[i];
				}
			}
			Logger.Warning($"AccessUtils ImplementedMethod: Implementation for {method} not found in {implementation}.");
			return null;
		}

		public static MethodInfo? MethodInfo(LambdaExpression lambda)
		{
			if (lambda == null)
			{
				Logger.Warning("AccessUtils MethodInfo: lambda is null.");
				return null;
			}
			if (lambda.Body is MethodCallExpression methodCallExpression)
			{
				return methodCallExpression.Method;
			}
			if (lambda.Body is UnaryExpression unaryExpression)
			{
				if (!(unaryExpression.Operand is MethodCallExpression methodCallExpression2))
				{
					Logger.Warning("AccessUtils MethodInfo: Expected a method call in lambda expression.");
					return null;
				}
				if (!(methodCallExpression2.Object is ConstantExpression constantExpression))
				{
					Logger.Warning("AccessUtils MethodInfo: Expected a method constant in lambda expression.");
					return null;
				}
				if (!(constantExpression.Value is MethodInfo result))
				{
					Logger.Warning($"AccessUtils MethodInfo: Expected constant to be of type {typeof(MethodInfo)} in lambda expression.");
					return null;
				}
				return result;
			}
			Logger.Warning($"AccessUtils MethodInfo: {lambda.Body.Type} is not a supported expression type.");
			return null;
		}
	}
	public sealed class BepInLoggerSource : ILogger
	{
		private readonly ManualLogSource _source;

		public BepInLoggerSource(ManualLogSource source)
		{
			Guard.NotNull<ManualLogSource>(source, "source");
			_source = source;
		}

		public void Debug(object? message)
		{
			_source.LogDebug(message);
		}

		public void Info(object? message)
		{
			_source.LogInfo(message);
		}

		public void Warning(object? message)
		{
			_source.LogWarning(message);
		}

		public void Error(object? message)
		{
			_source.LogError(message);
		}

		public void Fatal(object? message)
		{
			_source.LogFatal(message);
		}
	}
	public interface ICookieDependency
	{
		const string PluginId = "CookieFx";

		protected internal bool TrackOtherClients => false;

		protected internal void OnPlayerTracked(AbstractPlayer player)
		{
		}

		protected internal void OnPlayerUntracked(AbstractPlayer player)
		{
		}
	}
	public interface ILogger
	{
		public sealed class Unity : ILogger
		{
			public static readonly Unity Shared = new Unity();

			private Unity()
			{
			}

			public void Debug(object? message)
			{
				Debug.Log(message);
			}

			public void Info(object? message)
			{
				Debug.Log(message);
			}

			public void Warning(object? message)
			{
				Debug.LogWarning(message);
			}

			public void Error(object? message)
			{
				Debug.LogError(message);
			}

			public void Fatal(object? message)
			{
				Debug.LogError(message);
			}
		}

		void Debug(object? message);

		void Info(object? message);

		void Warning(object? message);

		void Error(object? message);

		void Fatal(object? message);
	}
	internal static class Logger
	{
		private static ILogger s_logger = ILogger.Unity.Shared;

		public static ILogger Source
		{
			get
			{
				return s_logger;
			}
			[param: AllowNull]
			set
			{
				s_logger = value ?? ILogger.Unity.Shared;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Debug(object message)
		{
			Source.Debug(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Info(object message)
		{
			Source.Info(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Warning(object message)
		{
			Source.Warning(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Error(object message)
		{
			Source.Error(message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Fatal(object message)
		{
			Source.Fatal(message);
		}
	}
	public static class PlayerUtils
	{
		public static ulong LocalPersistentId
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (StartOfRound.Instance == null)
				{
					throw new NetworkConfigurationException("Attempting to use netcode while not connected to server.");
				}
				PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController;
				return localPlayerController.playerSteamId;
			}
		}

		public static bool CanPersistLocal => StartOfRound.Instance != null;

		public static bool TryGetPersistentId(ulong networkId, out ulong persistentId)
		{
			if (StartOfRound.Instance == null)
			{
				persistentId = 0uL;
				return false;
			}
			if (!StartOfRound.Instance.ClientPlayerList.TryGetValue(networkId, out var value))
			{
				persistentId = 0uL;
				return false;
			}
			PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[value];
			persistentId = val.playerSteamId;
			return persistentId != 0;
		}

		public static bool CanPersist(ulong networkId)
		{
			int value;
			return CanPersistLocal && StartOfRound.Instance.ClientPlayerList.TryGetValue(networkId, out value) && StartOfRound.Instance.allPlayerScripts[value].playerSteamId != 0;
		}

		public static bool TryGetPlayerScript(int playerId, [NotNullWhen(true)] out PlayerControllerB? script)
		{
			if (StartOfRound.Instance == null)
			{
				script = null;
				return false;
			}
			StartOfRound instance = StartOfRound.Instance;
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			if (playerId < 0 || playerId >= allPlayerScripts.Length)
			{
				script = null;
				return false;
			}
			script = allPlayerScripts[playerId];
			return true;
		}

		public static bool TryGetPlayerScript(ulong networkId, [NotNullWhen(true)] out PlayerControllerB? script)
		{
			if (StartOfRound.Instance == null)
			{
				script = null;
				return false;
			}
			StartOfRound instance = StartOfRound.Instance;
			if (!instance.ClientPlayerList.TryGetValue(networkId, out var value))
			{
				script = null;
				return false;
			}
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			if (value < 0 || value >= allPlayerScripts.Length)
			{
				script = null;
				return false;
			}
			script = allPlayerScripts[value];
			return true;
		}

		public static void Disconnect(string? reason = null)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (!Networking.IsConnected || GameNetworkManager.Instance == null)
			{
				throw new NetworkConfigurationException("Attempting to use netcode while not connected to a server.");
			}
			GameNetworkManager.Instance.disconnectionReasonMessage = reason;
			GameNetworkManager.Instance.Disconnect();
		}

		public static void Disconnect(ulong networkId, string? reason = null)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!Networking.IsConnected || GameNetworkManager.Instance == null)
			{
				throw new NetworkConfigurationException("Attempting to use netcode while not connected to a server.");
			}
			if (networkId == Networking.Instance.LocalClientId)
			{
				Logger.Warning("Called non-local disconnect for local connection.");
				Disconnect(reason);
				return;
			}
			if (!Networking.Instance.IsServer && !Networking.Instance.IsHost)
			{
				throw new NetworkConfigurationException("Attempting to use server-only method on the client.");
			}
			Networking.Instance.Backend.DisconnectClient(networkId, reason);
		}
	}
	public static class PluginUtils
	{
		private static readonly Dictionary<Assembly, string?> PluginIdCache = new Dictionary<Assembly, string>();

		private static readonly HashSet<ICookieDependency> Dependencies = new HashSet<ICookieDependency>();

		public static void Register(ICookieDependency dependency)
		{
			Dependencies.Add(dependency);
		}

		public static bool TryGetPluginId(Assembly assembly, [NotNullWhen(true)] out string? pluginId)
		{
			if (PluginIdCache.TryGetValue(assembly, out string value))
			{
				pluginId = value;
				return value != null;
			}
			BepInPlugin val = (from x in AccessTools.GetTypesFromAssembly(assembly)
				select MetadataHelper.GetMetadata(x)).FirstOrDefault((Func<BepInPlugin, bool>)((BepInPlugin x) => x != null));
			if (val == null)
			{
				pluginId = null;
				PluginIdCache[assembly] = null;
				return false;
			}
			pluginId = val.GUID;
			PluginIdCache[assembly] = pluginId;
			return true;
		}

		public static void OnPlayerTracked(AbstractPlayer player)
		{
			foreach (ICookieDependency dependency in Dependencies)
			{
				try
				{
					if (dependency.TrackOtherClients || !(player is OtherClientPlayer))
					{
						dependency.OnPlayerTracked(player);
					}
				}
				catch (Exception ex)
				{
					Assembly assembly = dependency.GetType().Assembly;
					if (!TryGetPluginId(assembly, out string pluginId))
					{
						pluginId = assembly.FullName;
					}
					Logger.Error($"Player tracker by [{pluginId}] failed tracking net:{player.NetworkId} with {ex.Message}\n{ex.StackTrace}");
				}
			}
		}

		public static void OnPlayerUntracked(AbstractPlayer player)
		{
			foreach (ICookieDependency dependency in Dependencies)
			{
				try
				{
					if (dependency.TrackOtherClients || !(player is OtherClientPlayer))
					{
						dependency.OnPlayerUntracked(player);
					}
				}
				catch (Exception ex)
				{
					Assembly assembly = dependency.GetType().Assembly;
					if (!TryGetPluginId(assembly, out string pluginId))
					{
						pluginId = assembly.FullName;
					}
					Logger.Error($"Player tracker by [{pluginId}] failed untracking net:{player.NetworkId} with {ex.Message}\n{ex.StackTrace}");
				}
			}
		}
	}
	public static class SaveUtils
	{
		public static string ServerSavePath
		{
			get
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				if (!Networking.IsConnected || GameNetworkManager.Instance == null)
				{
					throw new NetworkConfigurationException("Attempting to use netcode while not hosting a server.");
				}
				if (!Networking.Instance.IsServer && !Networking.Instance.IsHost)
				{
					throw new NetworkConfigurationException("Attempting to use server-only method on the client.");
				}
				int saveFileNum = GameNetworkManager.Instance.saveFileNum;
				return Path.Combine(Application.persistentDataPath, "CookieFx", $"Save{saveFileNum + 1}");
			}
		}

		public static string ClientSavePath
		{
			get
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				if (!Networking.IsConnected || GameNetworkManager.Instance == null)
				{
					throw new NetworkConfigurationException("Attempting to use netcode while not hosting a server.");
				}
				if (!Networking.Instance.IsClient && !Networking.Instance.IsHost)
				{
					throw new NetworkConfigurationException("Attempting to use client-only method on the server.");
				}
				Guid serverId = Networking.Instance.Client.ServerSession.ServerId;
				return Path.Combine(Application.persistentDataPath, "CookieFx", "Servers", serverId.ToString("D"));
			}
		}

		public static void DeleteSave(int slot)
		{
			string path = Path.Combine(Application.persistentDataPath, "CookieFx", $"Save{slot + 1}");
			Logger.Warning($"Deleting save {slot + 1}");
			if (Directory.Exists(path))
			{
				Directory.Delete(path, recursive: true);
			}
		}
	}
}
namespace CookieFx.Patches
{
	internal static class FuckThisShitPatches
	{
		internal static void PatchTheirStuff(Harmony harmony)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method("StaticNetcodeLib.Messaging.UnnamedMessageHandler:ReceiveMessage", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(FuckThisShitPatches), "OnStaticNetcodeLib", (Type[])null, (Type[])null);
				if ((object)methodInfo != null)
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null);
					Logger.Info("[Compat] StaticNetcodeLib: Found");
				}
				else
				{
					Logger.Info("[Compat] StaticNetcodeLib: Not found");
				}
			}
			catch (Exception arg)
			{
				Logger.Error($"[Compat] StaticNetcodeLib: Failed\n{arg}");
			}
		}

		internal static IEnumerable<CodeInstruction> OnStaticNetcodeLib(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			MethodInfo target = AccessTools.DeclaredMethod(typeof(FuckThisShitPatches), "TryStaticNetcodeLib", (Type[])null, (Type[])null);
			Label label = generator.DefineLabel();
			yield return new CodeInstruction(OpCodes.Ldarga_S, (object)2);
			yield return new CodeInstruction(OpCodes.Call, (object)target);
			yield return new CodeInstruction(OpCodes.Brtrue, (object)label);
			yield return new CodeInstruction(OpCodes.Ret, (object)null);
			yield return new CodeInstruction(OpCodes.Nop, (object)null)
			{
				labels = { label }
			};
			foreach (CodeInstruction instruction in instructions)
			{
				yield return instruction;
			}
		}

		private static bool TryStaticNetcodeLib(in FastBufferReader reader)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			FastBufferReader val = reader;
			int position = ((FastBufferReader)(ref val)).Position;
			try
			{
				val = reader;
				string text = default(string);
				((FastBufferReader)(ref val)).ReadValueSafe(ref text, false);
				return text == "StaticNetcodeLib";
			}
			catch
			{
				return false;
			}
			finally
			{
				val = reader;
				((FastBufferReader)(ref val)).Seek(position);
			}
		}
	}
	[HarmonyPatch(typeof(NetworkManager))]
	[HarmonyPriority(500)]
	[HarmonyWrapSafe]
	internal static class NetworkManagerPatch
	{
		[HarmonyPatch("Initialize")]
		[HarmonyPostfix]
		public static void InitializePatch(NetworkManager __instance)
		{
			Networking.Initialize(__instance);
		}

		[HarmonyPatch("ShutdownInternal")]
		[HarmonyPrefix]
		public static void ShutdownPatch()
		{
			Networking.Shutdown();
		}
	}
	[HarmonyPatch]
	[HarmonyPriority(500)]
	[HarmonyWrapSafe]
	internal static class SavePatches
	{
		[HarmonyPatch(typeof(GameNetworkManager), "SaveGame")]
		[HarmonyPrefix]
		private static void SaveGame()
		{
			if (Networking.IsConnected)
			{
				Networking instance = Networking.Instance;
				if (instance.IsClient)
				{
					Logger.Info("Saving client...");
					instance.Client.Save();
				}
				if (instance.IsServer)
				{
					Logger.Info("Saving server...");
					instance.Server.Save();
				}
			}
		}

		[HarmonyPatch(typeof(DeleteFileButton), "DeleteFile")]
		[HarmonyPostfix]
		private static void OnDeleteFile(DeleteFileButton __instance)
		{
			DeleteFile(__instance.fileToDelete);
		}

		private static void DeleteFile(int slot)
		{
			SaveUtils.DeleteSave(slot);
		}

		internal static IEnumerable<CodeInstruction> DeleteFileBetterSaves(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo target = AccessTools.Method("LCBetterSaves.Plugin:InitializeBetterSaves", (Type[])null, (Type[])null);
			Type fieldHolder = AccessTools.TypeByName("DeleteFileButton_BetterSaves");
			FieldInfo targetField = AccessTools.DeclaredField(fieldHolder, "fileToDelete");
			MethodInfo deleteCall = AccessUtils.MethodInfo((Expression<Func<Action<int>>>)(() => DeleteFile));
			bool found = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (!found && CodeInstructionExtensions.Calls(instruction, target))
				{
					yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					yield return new CodeInstruction(OpCodes.Ldfld, (object)targetField);
					yield return new CodeInstruction(OpCodes.Call, (object)deleteCall);
					yield return instruction;
					found = true;
				}
				else
				{
					yield return instruction;
				}
			}
			if (!found)
			{
				Logger.Error("Failed to patch LCBetterSaves delete file button.");
			}
		}
	}
}
namespace CookieFx.Network
{
	public static class ClientNetworking
	{
		private interface IHandler
		{
			object PayloadType { get; }

			Type Type { get; }

			void Invoke(ClientPlayer player, FastBufferReader reader);
		}

		private sealed class Handler<T> : IHandler where T : NetworkPayload<T>
		{
			public NetworkPayloadType<T> PayloadType { get; }

			public Action<ClientPlayer, T> Action { get; }

			object IHandler.PayloadType => PayloadType;

			Type IHandler.Type => typeof(T);

			internal Handler(NetworkPayloadType<T> type, Action<ClientPlayer, T> action)
			{
				Guard.NotNull(type, "type");
				Guard.NotNull(action, "action");
				PayloadType = type;
				Action = action;
			}

			public void Invoke(ClientPlayer player, FastBufferReader reader)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				Guard.NotNull(player, "player");
				T val;
				try
				{
					val = PayloadType.Factory(reader);
					Guard.NotNull(val, "payload");
				}
				catch (Exception ex)
				{
					Logger.Error("Decoding clientbound payload [" + PayloadType.Channel + "] from server failed: " + ex.Message + "\n" + ex.StackTrace);
					player.Disconnect("Invalid Packet Data from Server");
					return;
				}
				try
				{
					Action(player, val);
				}
				catch (Exception ex2)
				{
					Logger.Error("Invoking handler for clientbound payload [" + PayloadType.Channel + "] from server failed: " + ex2.Message + "\n" + ex2.StackTrace);
					player.Disconnect("Broken Handler");
				}
			}

			public void InvokeLocal(ClientPlayer player, T payload)
			{
				Guard.NotNull(player, "player");
				Guard.NotNull(payload, "payload");
				try
				{
					Action(player, payload);
				}
				catch (Exception ex)
				{
					Logger.Error("Invoking handler for clientbound payload [" + PayloadType.Channel + "] from local server failed: " + ex.Message + "\n" + ex.StackTrace);
					player.Disconnect("Broken Handler");
				}
			}
		}

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

		public static event Action<NetworkSession>? OnSetupComplete;

		public static event Action<NetworkSession, string>? OnServerChannelRegister;

		public static event Action<NetworkSession, string>? OnServerChannelUnregister;

		public static ICollection<string> GetReceived()
		{
			return Handlers.Keys;
		}

		public static ICollection<string> GetSendable()
		{
			return Networking.Instance?.Client?.ServerSession?.SendableChannels ?? new List<string>();
		}

		public static bool CanSend(string channel)
		{
			Guard.NotNullOrEmpty(channel, "channel");
			if (!Networking.IsConnected || !Networking.Instance.IsClient)
			{
				return false;
			}
			return Networking.Instance.Client.ServerSession.SendableChannels.Contains(channel);
		}

		public static bool Send<T>(T payload) where T : NetworkPayload<T>
		{
			//IL_001f: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNull(payload, "payload");
			if (!Networking.IsConnected)
			{
				throw new NetworkConfigurationException("Attempting to use netcode while not connected to a server.");
			}
			if (!Networking.Instance.IsClient)
			{
				throw new NetworkConfigurationException("Attempting to use client-only method on the server.");
			}
			if (payload.PayloadType.Side == NetworkSide.Clientbound)
			{
				throw new NetworkConfigurationException("Attempting to send clientbound payload to the server.");
			}
			if (CanSend(payload.PayloadType.Channel))
			{
				SendCore(Networking.Instance.Client, payload);
				return true;
			}
			return false;
		}

		public static bool Send<T>(NetworkPayloadType<T> type, Func<T> factory) where T : NetworkPayload<T>
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNull(type, "type");
			Guard.NotNull(factory, "factory");
			if (!Networking.IsConnected)
			{
				throw new NetworkConfigurationException("Attempting to use netcode while not connected to a server.");
			}
			if (!Networking.Instance.IsClient)
			{
				throw new NetworkConfigurationException("Attempting to use client-only method on the server.");
			}
			if (type.Side == NetworkSide.Clientbound)
			{
				throw new NetworkConfigurationException("Attempting to send clientbound payload to the server.");
			}
			if (CanSend(type.Channel))
			{
				T val = factory();
				Guard.NotNull(val, "payload");
				SendCore(Networking.Instance.Client, val);
				return true;
			}
			return false;
		}

		private static void SendCore<T>(GameClient client, T payload) where T : NetworkPayload<T>
		{
			//IL_006d: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			T payload2 = payload;
			Networking networking2 = client.Networking;
			NetworkSession.Server serverSession = client.ServerSession;
			if (serverSession.IsLocal)
			{
				Logger.Debug("Invoking local server payload on channel [" + payload2.PayloadType.Channel + "]");
				Networking.EnqueueTask(delegate(Networking networking)
				{
					ServerNetworking.InvokeLocal(networking, payload2);
				});
				return;
			}
			FastBufferWriter writer = Networking.EncodePayload(payload2);
			try
			{
				networking2.SendBackendMessage(serverSession.NetworkId, writer);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref writer)).Dispose();
			}
		}

		public static Action<ClientPlayer, T>? Register<T>(NetworkPayloadType<T> type, Action<ClientPlayer, T> callback) where T : NetworkPayload<T>
		{
			//IL_002c: 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)
			Guard.NotNull(type, "type");
			Guard.NotNull(callback, "callback");
			if (type.Side == NetworkSide.Serverbound)
			{
				throw new NetworkConfigurationException("Attempting to register serverbound payload to the client.");
			}
			bool flag = false;
			Action<ClientPlayer, T> result = null;
			if (Handlers.TryGetValue(type.Channel, out IHandler value))
			{
				flag = true;
				if (value is Handler<T> handler)
				{
					result = handler.Action;
				}
			}
			else if (Handlers.Count >= 8192)
			{
				throw new InvalidOperationException($"Client tried to register more than {8192} channels.");
			}
			Handlers[type.Channel] = new Handler<T>(type, callback);
			if (!flag && Networking.IsConnected)
			{
				Networking instance = Networking.Instance;
				if (!instance.IsClient)
				{
					throw new NetworkConfigurationException("Attempting to use client-only method on the server.");
				}
				GameClient client = instance.Client;
				NetworkSession.Server serverSession = client.ServerSession;
				if (serverSession.IsLocal)
				{
					OnChannelRegister(serverSession, type.Channel);
				}
				else if (serverSession.EagerlySyncChannels)
				{
					instance.SendChannel(serverSession.NetworkId, type.Channel, register: true);
				}
			}
			return result;
		}

		public static void Unregister(string channel)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNullOrEmpty(channel, "channel");
			if (Handlers.Remove(channel) && Networking.IsConnected)
			{
				Networking instance = Networking.Instance;
				if (!instance.IsClient)
				{
					throw new NetworkConfigurationException("Attempting to use client-only method on the server.");
				}
				GameClient client = instance.Client;
				NetworkSession.Server serverSession = client.ServerSession;
				if (serverSession.IsLocal)
				{
					OnChannelUnregister(serverSession, channel);
				}
				else if (serverSession.EagerlySyncChannels)
				{
					instance.SendChannel(serverSession.NetworkId, channel, register: false);
				}
			}
		}

		public static void Unregister<T>(NetworkPayloadType<T> type) where T : NetworkPayload<T>
		{
			Guard.NotNull(type, "type");
			Unregister(type.Channel);
		}

		internal static void Invoke(Networking networking, string channel, FastBufferReader reader)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNull(networking, "networking");
			Guard.NotNullOrWhiteSpace(channel, "channel");
			if (!networking.IsClient)
			{
				throw new NetworkConfigurationException("Attempting to use client-only method on the server.");
			}
			GameClient client = networking.Client;
			IHandler value;
			if (!client.IsReady)
			{
				Logger.Warning("Received clientbound payload on channel [" + channel + "] from server before we are ready to accept them.");
				client.ServerSession.Disconnect("Sending payloads before finishing setup is disallowed.");
			}
			else if (Handlers.TryGetValue(channel, out value))
			{
				value.Invoke(client.Player, reader);
			}
			else
			{
				Logger.Warning("Received clientbound payload on channel [" + channel + "] from server but it has no handlers.");
			}
		}

		internal static void InvokeLocal<T>(Networking networking, T payload) where T : NetworkPayload<T>
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNull(networking, "networking");
			Guard.NotNull(payload, "payload");
			if (!networking.IsHost)
			{
				throw new NetworkConfigurationException("Attempting to use host-only method on non-host.");
			}
			string channel = payload.PayloadType.Channel;
			GameClient client = networking.Client;
			IHandler value;
			if (!client.IsReady)
			{
				Logger.Warning("Received clientbound payload on channel [" + channel + "] from server before we are ready to accept them.");
				client.ServerSession.Disconnect("Sending payloads before finishing setup is disallowed.");
			}
			else if (Handlers.TryGetValue(channel, out value))
			{
				if (!(value is Handler<T> handler))
				{
					Logger.Error($"Received clientbound payload on channel [{channel}] from local server but the handler is the wrong type. (Expected: {typeof(T)}, Registered: {value.Type})");
					client.ServerSession.Disconnect("Unexpected Handler Type");
				}
				else if (payload.PayloadType != value.PayloadType)
				{
					Logger.Error("Received clientbound payload on channel [" + channel + "] from local server but the payload type is not the expected reference.");
					client.ServerSession.Disconnect("Unexpected Type Reference");
				}
				else
				{
					handler.InvokeLocal(client.Player, payload);
				}
			}
			else
			{
				Logger.Warning("Received clientbound payload on channel [" + channel + "] from local server but it has no handlers.");
			}
		}

		internal static void OnChannelRegister(NetworkSession session, string channel)
		{
			Delegate[] array = ClientNetworking.OnServerChannelRegister?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<NetworkSession, string>)@delegate)(session, channel);
				}
				catch (Exception ex)
				{
					Logger.Error("Client networking channel register [" + channel + "] from server failed: " + ex.Message + "\n" + ex.StackTrace);
				}
			}
		}

		internal static void OnChannelUnregister(NetworkSession session, string channel)
		{
			Delegate[] array = ClientNetworking.OnServerChannelUnregister?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<NetworkSession, string>)@delegate)(session, channel);
				}
				catch (Exception ex)
				{
					Logger.Error("Client networking channel unregister [" + channel + "] from server failed: " + ex.Message + "\n" + ex.StackTrace);
				}
			}
		}

		internal static void OnSetupSuccess(NetworkSession session)
		{
			Delegate[] array = ClientNetworking.OnSetupComplete?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<NetworkSession>)@delegate)(session);
				}
				catch (Exception ex)
				{
					Logger.Error("Client networking setup complete from server failed: " + ex.Message + "\n" + ex.StackTrace);
				}
			}
		}
	}
	public sealed class Networking
	{
		internal const int MaxChannels = 8192;

		internal const int MaxChannelNameSize = 128;

		internal static readonly byte[] LibraryIdentifier = Encoding.UTF8.GetBytes("CookieFx");

		internal static readonly byte[] ChannelIdentifier = Encoding.UTF8.GetBytes("CookieCh");

		internal static readonly int IdentifierSize = FastBufferWriter.GetWriteSize<byte>(LibraryIdentifier, -1, 0);

		private static readonly ConcurrentQueue<Action<Networking>> TaskQueue = new ConcurrentQueue<Action<Networking>>();

		public const ulong ServerClientId = 0uL;

		[MemberNotNullWhen(true, "Instance")]
		public static bool IsConnected
		{
			[MemberNotNullWhen(true, "Instance")]
			get
			{
				return Instance != null;
			}
		}

		public static Networking? Instance { get; private set; }

		public ulong LocalClientId => Backend.LocalClientId;

		[MemberNotNullWhen(true, "Client")]
		[MemberNotNullWhen(false, "Server")]
		public bool IsClient
		{
			[MemberNotNullWhen(true, "Client")]
			[MemberNotNullWhen(false, "Server")]
			get
			{
				return Backend.IsClient;
			}
		}

		[MemberNotNullWhen(true, "Server")]
		[MemberNotNullWhen(false, "Client")]
		public bool IsServer
		{
			[MemberNotNullWhen(true, "Server")]
			[MemberNotNullWhen(false, "Client")]
			get
			{
				return Backend.IsServer;
			}
		}

		[MemberNotNullWhen(true, new string[] { "Client", "Server" })]
		public bool IsHost
		{
			[MemberNotNullWhen(true, new string[] { "Client", "Server" })]
			get
			{
				return Backend.IsHost;
			}
		}

		public NetworkManager Backend { get; }

		public GameClient? Client { get; private set; }

		public AbstractServer? Server { get; private set; }

		public static event Action<Networking>? OnInitialize;

		public static event Action<Networking>? OnShutdown;

		public static event Action<Networking, ServerPlayer>? OnPlayerConnected;

		public static event Action<Networking, ServerPlayer>? OnPlayerDisconnect;

		public static event Action<Networking>? OnTick;

		public static void EnqueueTask(Action<Networking> task)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNull(task, "task");
			if (!IsConnected)
			{
				throw new NetworkConfigurationException("Attempting to use netcode while not connected to a server.");
			}
			TaskQueue.Enqueue(task);
		}

		public static void Initialize(NetworkManager backend)
		{
			Guard.NotNull<NetworkManager>(backend, "backend");
			if (backend != NetworkManager.Singleton)
			{
				Logger.Warning("The Unity Network Manager is not a singleton, which is unexpected.");
			}
			if (Instance != null)
			{
				Logger.Info("Shutdown");
				Instance.Destroy();
				TaskQueue.Clear();
			}
			Logger.Info("Initialize");
			Instance = new Networking(backend);
			Instance.Startup();
		}

		public static void Shutdown()
		{
			Logger.Info("Shutdown");
			if (Instance != null)
			{
				Instance.Destroy();
				Instance = null;
				TaskQueue.Clear();
			}
		}

		private Networking(NetworkManager backend)
		{
			Guard.NotNull<NetworkManager>(backend, "backend");
			Backend = backend;
		}

		private void Startup()
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			if (Backend.IsClient || Backend.IsHost)
			{
				Client = GameClient.StartClient(this);
			}
			if (Backend.IsServer || Backend.IsHost)
			{
				if (Client != null)
				{
					Server = Client.StartHost();
				}
				else
				{
					Server = DedicatedServer.StartServer(this);
				}
				Backend.OnClientConnectedCallback += OnClientConnectedCallback;
				Backend.OnClientDisconnectCallback += OnClientDisconnectCallback;
			}
			Backend.NetworkTickSystem.Tick += OnNetworkTick;
			Backend.CustomMessagingManager.OnUnnamedMessage += new UnnamedMessageDelegate(OnBackendMessage);
			InvokeInitialize();
		}

		private void Destroy()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			InvokeShutdown();
			Client?.OnShuttingDown();
			if (Server != null)
			{
				Server.OnShutdown();
				Server = null;
				Backend.OnClientConnectedCallback -= OnClientConnectedCallback;
				Backend.OnClientDisconnectCallback -= OnClientDisconnectCallback;
			}
			Backend.NetworkTickSystem.Tick -= OnNetworkTick;
			Backend.CustomMessagingManager.OnUnnamedMessage -= new UnnamedMessageDelegate(OnBackendMessage);
		}

		public static int GetChannelHeaderSize(string channel)
		{
			return IdentifierSize + FastBufferWriter.GetWriteSize(channel, false);
		}

		internal static FastBufferWriter EncodePayload<T>(T payload) where T : NetworkPayload<T>
		{
			//IL_011d: 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_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			NetworkPayloadType<T> payloadType = payload.PayloadType;
			int estimatedSize = payload.GetEstimatedSize();
			int num = payloadType.HeaderSize + estimatedSize;
			if (estimatedSize < 0)
			{
				throw new InvalidOperationException($"The payload on channel [{payloadType.Channel}] estimates a negative size of {estimatedSize} bytes.");
			}
			if (num > 65535)
			{
				Logger.Warning($"The payload on channel [{payloadType.Channel}] estimates of {num} bytes (of which {payloadType.HeaderSize} bytes is the header). This is larger than the recommended max size of {ushort.MaxValue} bytes. The message may be dropped during transit.");
			}
			int num2 = num * 2;
			if (num2 < num)
			{
				num2 = int.MaxValue;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(num, (Allocator)2, Math.Max(65535, num2));
			try
			{
				if (!((FastBufferWriter)(ref val)).TryBeginWrite(num))
				{
					throw new OutOfMemoryException($"The required buffer {((FastBufferWriter)(ref val)).MaxCapacity} is too small to write the payload of at least {num} bytes.");
				}
				((FastBufferWriter)(ref val)).WriteUnmanagedSafe<byte>(ChannelIdentifier);
				((FastBufferWriter)(ref val)).WriteValueSafe(payloadType.Channel, false);
				payload.Encode(val);
				return val;
			}
			catch
			{
				((FastBufferWriter)(ref val)).Dispose();
				throw;
			}
		}

		internal void SendBackendMessage(ulong networkId, FastBufferWriter writer)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Backend.CustomMessagingManager.SendUnnamedMessage(networkId, writer, (NetworkDelivery)4);
		}

		internal void SendBackendMessage(ulong[] networkId, FastBufferWriter writer)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (networkId.Length != 0)
			{
				if (networkId.Length == 1)
				{
					Backend.CustomMessagingManager.SendUnnamedMessage(networkId[0], writer, (NetworkDelivery)4);
				}
				else
				{
					Backend.CustomMessagingManager.SendUnnamedMessage((IReadOnlyList<ulong>)networkId, writer, (NetworkDelivery)4);
				}
			}
		}

		private void OnBackendMessage(ulong senderId, FastBufferReader reader)
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			if (!((FastBufferReader)(ref reader)).TryBeginRead(IdentifierSize))
			{
				return;
			}
			byte[] array = default(byte[]);
			((FastBufferReader)(ref reader)).ReadUnmanagedSafe<byte>(ref array);
			if (array.AsSpan().SequenceEqual(ChannelIdentifier))
			{
				string text = default(string);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false);
				if (senderId != 0L && !IsServer)
				{
					Logger.Error($"Received unexpected payload on channel [{text}] from client {senderId}, we only accept messages from the server.");
				}
				else if (senderId == Backend.LocalClientId)
				{
					Logger.Error("Received unexpected payload on channel [" + text + "] from local host or server, we only accept messages from others.");
				}
				else if (senderId == 0)
				{
					Logger.Debug("Received client payload on channel [" + text + "] from server");
					ClientNetworking.Invoke(this, text, reader);
				}
				else
				{
					Logger.Debug($"Received server payload [{text}] from client {senderId}");
					ServerNetworking.Invoke(this, senderId, text, reader);
				}
			}
			else if (array.AsSpan().SequenceEqual(LibraryIdentifier))
			{
				InternalPayloadType internalPayloadType = default(InternalPayloadType);
				((FastBufferReader)(ref reader)).ReadValueSafe<InternalPayloadType>(ref internalPayloadType, default(ForEnums));
				if (senderId != 0L && !IsServer)
				{
					Logger.Error($"Received unexpected internal payload [{internalPayloadType}] from client {senderId}. We only accept messages from the server.");
					return;
				}
				if (senderId == Backend.LocalClientId)
				{
					Logger.Error($"Received unexpected internal payload [{internalPayloadType}] from local host or server. We only accept encoded messages from non-local sources.");
					return;
				}
				Logger.Info(string.Format("Received internal payload [{0}] from {1}", internalPayloadType, (senderId == 0L) ? "server" : $"client {senderId}"));
				OnInternalMessage(senderId, internalPayloadType, reader);
			}
		}

		private void OnNetworkTick()
		{
			Action<Networking> result;
			while (TaskQueue.TryDequeue(out result))
			{
				try
				{
					result(this);
				}
				catch (Exception ex)
				{
					Logger.Error("Network tick failed in task queue. " + ex.Message + "\n" + ex.StackTrace);
				}
			}
			Delegate[] array = Networking.OnTick?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<Networking>)@delegate)(this);
				}
				catch (Exception ex2)
				{
					Logger.Error("Network tick failed. " + ex2.Message + "\n" + ex2.StackTrace);
				}
			}
		}

		private void OnClientConnectedCallback(ulong clientId)
		{
			if (Server == null)
			{
				PlayerUtils.Disconnect(clientId, "No active server.");
				return;
			}
			Logger.Info($"Client added: {clientId}");
			Server.PlayerManager.OnClientAdded(clientId);
		}

		private void OnClientDisconnectCallback(ulong clientId)
		{
			if (Server == null)
			{
				PlayerUtils.Disconnect(clientId, "No active server.");
				return;
			}
			Logger.Info($"Client removed: {clientId}");
			Server.PlayerManager.OnClientRemoved(clientId);
		}

		internal void InvokePlayerConnected(ServerPlayer player)
		{
			Delegate[] array = Networking.OnPlayerConnected?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<Networking, ServerPlayer>)@delegate)(this, player);
				}
				catch (Exception ex)
				{
					Logger.Error("Networking event [Player Connected] failed. " + ex.Message + "\n" + ex.StackTrace);
				}
			}
		}

		internal void InvokePlayerDisconnected(ServerPlayer player)
		{
			Delegate[] array = Networking.OnPlayerDisconnect?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<Networking, ServerPlayer>)@delegate)(this, player);
				}
				catch (Exception ex)
				{
					Logger.Error("Networking event [Player Disconnect] failed. " + ex.Message + "\n" + ex.StackTrace);
				}
			}
		}

		internal void InvokeInitialize()
		{
			Delegate[] array = Networking.OnInitialize?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<Networking>)@delegate)(this);
				}
				catch (Exception ex)
				{
					Logger.Error("Networking event [Initialize] failed. " + ex.Message + "\n" + ex.StackTrace);
				}
			}
		}

		internal void InvokeShutdown()
		{
			Delegate[] array = Networking.OnShutdown?.GetInvocationList();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Delegate[] array2 = array;
			foreach (Delegate @delegate in array2)
			{
				try
				{
					((Action<Networking>)@delegate)(this);
				}
				catch (Exception ex)
				{
					Logger.Error("Networking event [Shutdown] failed. " + ex.Message + "\n" + ex.StackTrace);
				}
			}
		}

		private void OnInternalMessage(ulong senderId, InternalPayloadType type, FastBufferReader reader)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetSession(senderId, out NetworkSession session))
			{
				Logger.Error($"Couldn't find session for {senderId} while receiving internal payload.");
				PlayerUtils.Disconnect(senderId, "Unknown NetworkId");
				return;
			}
			switch (type)
			{
			case InternalPayloadType.Setup:
				OnSetupRequest(session, reader);
				break;
			case InternalPayloadType.SetupComplete:
				session.OnSetupComplete(this);
				break;
			case InternalPayloadType.TrackPlayers:
				OnTrackPlayers(session, reader);
				break;
			case InternalPayloadType.UntrackPlayers:
				OnUntrackPlayers(session, reader);
				break;
			case InternalPayloadType.RegisterChannels:
				OnRegisterChannels(session, reader);
				break;
			case InternalPayloadType.UnregisterChannels:
				OnUnregisterChannels(session, reader);
				break;
			default:
				Logger.Error($"Received unknown internal payload [{type}] from [{senderId}]");
				break;
			}
		}

		private bool TryGetSession(ulong senderId, [MaybeNullWhen(false)] out NetworkSession session)
		{
			if (senderId == 0)
			{
				if (!IsClient)
				{
					session = null;
					return false;
				}
				session = Client.ServerSession;
				return true;
			}
			if (!IsServer)
			{
				session = null;
				return false;
			}
			if (Server.PlayerManager.TryGetSession(senderId, out NetworkSession.Client session2))
			{
				session = session2;
				return true;
			}
			session = null;
			return false;
		}

		internal static FastBufferWriter PrepareInternalPayload(InternalPayloadType type, int size)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			size += IdentifierSize + FastBufferWriter.GetWriteSize<InternalPayloadType>(ref type, default(ForStructs));
			FastBufferWriter result = default(FastBufferWriter);
			((FastBufferWriter)(ref result))..ctor(size, (Allocator)2, -1);
			try
			{
				if (!((FastBufferWriter)(ref result)).TryBeginWrite(size))
				{
					throw new OutOfMemoryException($"The required buffer {((FastBufferWriter)(ref result)).MaxCapacity} is too small to write the internal payload of exactly {size} bytes.");
				}
				((FastBufferWriter)(ref result)).WriteUnmanagedSafe<byte>(LibraryIdentifier);
				((FastBufferWriter)(ref result)).WriteValueSafe<InternalPayloadType>(ref type, default(ForEnums));
				return result;
			}
			catch
			{
				((FastBufferWriter)(ref result)).Dispose();
				throw;
			}
		}

		internal void SendAllPlayers(ulong networkId, AbstractPlayerManager manager)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNull(manager, "manager");
			ServerPlayer[] array = manager.PlayersExcept(networkId).ToArray();
			if (array.Length == 0)
			{
				return;
			}
			int num = FastBufferWriter.GetWriteSize<int>();
			ServerPlayer[] array2 = array;
			foreach (ServerPlayer serverPlayer in array2)
			{
				num += FastBufferWriter.GetWriteSize<ulong>() + FastBufferWriter.GetWriteSize<ulong>();
			}
			FastBufferWriter writer = PrepareInternalPayload(InternalPayloadType.TrackPlayers, num);
			try
			{
				int num2 = array.Length;
				((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num2, default(ForPrimitives));
				ServerPlayer[] array3 = array;
				foreach (ServerPlayer serverPlayer2 in array3)
				{
					ulong networkId2 = serverPlayer2.NetworkId;
					((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref networkId2, default(ForPrimitives));
					networkId2 = serverPlayer2.PersistentId;
					((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref networkId2, default(ForPrimitives));
				}
				Logger.Info(string.Format("Sent tracking for [{0}] to net:{1}", string.Join(", ", (IEnumerable<ServerPlayer>)array), networkId));
				SendBackendMessage(networkId, writer);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref writer)).Dispose();
			}
		}

		internal void SendPlayerTracking(AbstractPlayerManager manager, ServerPlayer player, bool track)
		{
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: 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_0161: 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)
			Guard.NotNull(manager, "manager");
			Guard.NotNull(player, "player");
			if (manager is IntegratedPlayerManager integratedPlayerManager && !player.Session.IsLocal)
			{
				if (track)
				{
					integratedPlayerManager.Client.PlayerManager.OnPlayerTracked(player.NetworkId, player.PersistentId);
				}
				else
				{
					integratedPlayerManager.Client.PlayerManager.OnPlayerUntracked(player.NetworkId);
				}
			}
			ulong[] array = (from p in manager.PlayersExcept(player.NetworkId)
				where p.Session.EagerlySyncPlayers && !p.Session.IsLocal
				select p.NetworkId).ToArray();
			if (array.Length == 0)
			{
				return;
			}
			int num = FastBufferWriter.GetWriteSize<int>() + FastBufferWriter.GetWriteSize<ulong>();
			if (track)
			{
				num += FastBufferWriter.GetWriteSize<ulong>();
			}
			FastBufferWriter writer = PrepareInternalPayload(track ? InternalPayloadType.TrackPlayers : InternalPayloadType.UntrackPlayers, num);
			try
			{
				int num2 = 1;
				((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num2, default(ForPrimitives));
				ulong networkId = player.NetworkId;
				((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref networkId, default(ForPrimitives));
				if (track)
				{
					networkId = player.PersistentId;
					((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref networkId, default(ForPrimitives));
				}
				Logger.Info(string.Format("Sent tracking for {0} to [{1}]", player, string.Join(", ", array)));
				SendBackendMessage(array, writer);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref writer)).Dispose();
			}
		}

		internal void SendChannel(ulong networkId, string channel, bool register)
		{
			SendChannel(new ulong[1] { networkId }, channel, register);
		}

		internal void SendChannel(ulong[] networkIds, string channel, bool register)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			Guard.NotNull(networkIds, "networkIds");
			Guard.NotNullOrEmpty(channel, "channel");
			if (networkIds.Length == 0)
			{
				return;
			}
			int writeSize = FastBufferWriter.GetWriteSize<int>();
			writeSize += FastBufferWriter.GetWriteSize(channel, false);
			FastBufferWriter writer = PrepareInternalPayload(register ? InternalPayloadType.RegisterChannels : InternalPayloadType.UnregisterChannels, writeSize);
			try
			{
				int num = 1;
				((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref writer)).WriteValueSafe(channel, false);
				SendBackendMessage(networkIds, writer);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref writer)).Dispose();
			}
		}

		internal void SendChannels(ulong networkId, ICollection<string> channels, bool register)
		{
			SendChannels(new ulong[1] { networkId }, channels, register);
		}

		internal void SendChannels(ulong[] networkIds, ICollection<string> channels, bool register)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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)
			Guard.NotNull(networkIds, "networkIds");
			Guard.NotNull(channels, "channels");
			if (networkIds.Length == 0 || channels.Count == 0)
			{
				return;
			}
			int num = FastBufferWriter.GetWriteSize<int>();
			foreach (string channel in channels)
			{
				num += FastBufferWriter.GetWriteSize(channel, false);
			}
			FastBufferWriter writer = PrepareInternalPayload(register ? InternalPayloadType.RegisterChannels : InternalPayloadType.UnregisterChannels, num);
			try
			{
				int count = channels.Count;
				((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref count, default(ForPrimitives));
				foreach (string channel2 in channels)
				{
					((FastBufferWriter)(ref writer)).WriteValueSafe(channel2, false);
				}
				SendBackendMessage(networkIds, writer);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref writer)).Dispose();
			}
		}

		private static void OnRegisterChannels(NetworkSession session, FastBufferReader reader)
		{
			//IL_0048: 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)
			string text = ((session.NetworkId == 0L) ? "server" : $"client {session.NetworkId}");
			Logger.Info("Registering channels from " + text);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			string item = default(string);
			for (int i = 0; i < num; i++)
			{
				((FastBufferReader)(ref reader)).ReadValueSafe(ref item, false);
				hashSet.Add(item);
			}
			if (num != hashSet.Count)
			{
				Logger.Warning("Received duplicate channels in register channels payload from " + text);
			}
			session.OnRegisterChannels(hashSet);
		}

		private static