Decompiled source of MashGamemodeLibrary v1.0.5

Mods/MashGamemodeLibrary.dll

Decompiled 3 weeks ago
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using AudioImportLib;
using BoneLib;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Interaction;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Audio;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Forklift.Model;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.VRMK;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppUltEvents;
using LabFusion.Data;
using LabFusion.Downloading;
using LabFusion.Downloading.ModIO;
using LabFusion.Entities;
using LabFusion.Extensions;
using LabFusion.Marrow;
using LabFusion.Marrow.Extenders;
using LabFusion.Marrow.Patching;
using LabFusion.Marrow.Pool;
using LabFusion.Menu.Data;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Player;
using LabFusion.Preferences;
using LabFusion.Preferences.Client;
using LabFusion.RPC;
using LabFusion.SDK.Gamemodes;
using LabFusion.SDK.Modules;
using LabFusion.SDK.Points;
using LabFusion.Safety;
using LabFusion.Scene;
using LabFusion.Senders;
using LabFusion.UI.Popups;
using LabFusion.Utilities;
using MashGamemodeLibrary;
using MashGamemodeLibrary.Audio.Containers;
using MashGamemodeLibrary.Audio.Loaders;
using MashGamemodeLibrary.Audio.Modifiers;
using MashGamemodeLibrary.Audio.Music;
using MashGamemodeLibrary.Audio.Players.Basic;
using MashGamemodeLibrary.Audio.Players.Basic.Providers;
using MashGamemodeLibrary.Audio.Players.Extensions;
using MashGamemodeLibrary.Audio.Registry;
using MashGamemodeLibrary.Config;
using MashGamemodeLibrary.Config.Menu;
using MashGamemodeLibrary.Config.Menu.Attributes;
using MashGamemodeLibrary.Config.Menu.Element;
using MashGamemodeLibrary.Context;
using MashGamemodeLibrary.Context.Control;
using MashGamemodeLibrary.Context.Helper;
using MashGamemodeLibrary.Data.Random;
using MashGamemodeLibrary.Entities;
using MashGamemodeLibrary.Entities.Association;
using MashGamemodeLibrary.Entities.Association.Impl;
using MashGamemodeLibrary.Entities.Behaviour;
using MashGamemodeLibrary.Entities.Behaviour.Cache;
using MashGamemodeLibrary.Entities.Behaviour.Helpers;
using MashGamemodeLibrary.Entities.ECS;
using MashGamemodeLibrary.Entities.ECS.Attributes;
using MashGamemodeLibrary.Entities.ECS.BaseComponents;
using MashGamemodeLibrary.Entities.ECS.Declerations;
using MashGamemodeLibrary.Entities.ECS.Instance;
using MashGamemodeLibrary.Entities.ECS.Networking;
using MashGamemodeLibrary.Entities.Extenders;
using MashGamemodeLibrary.Entities.Interaction;
using MashGamemodeLibrary.Entities.Interaction.Grabbing;
using MashGamemodeLibrary.Entities.Queries;
using MashGamemodeLibrary.Environment.State;
using MashGamemodeLibrary.Execution;
using MashGamemodeLibrary.Integrations;
using MashGamemodeLibrary.Loadout;
using MashGamemodeLibrary.Networking.Remote;
using MashGamemodeLibrary.Networking.Variable.Encoder.Util;
using MashGamemodeLibrary.Patches;
using MashGamemodeLibrary.Phase;
using MashGamemodeLibrary.Player;
using MashGamemodeLibrary.Player.Actions;
using MashGamemodeLibrary.Player.Data;
using MashGamemodeLibrary.Player.Data.Components.Visibility.Parts;
using MashGamemodeLibrary.Player.Data.Events.Callers;
using MashGamemodeLibrary.Player.Data.Events.Data;
using MashGamemodeLibrary.Player.Data.Extenders;
using MashGamemodeLibrary.Player.Data.Extenders.Colliders.Caches;
using MashGamemodeLibrary.Player.Data.Extenders.Colliders.Data;
using MashGamemodeLibrary.Player.Data.Extenders.Visibility;
using MashGamemodeLibrary.Player.Data.Extenders.Visibility.Parts;
using MashGamemodeLibrary.Player.Data.Rules;
using MashGamemodeLibrary.Player.Data.Rules.Networking;
using MashGamemodeLibrary.Player.Data.Rules.Rules;
using MashGamemodeLibrary.Player.Helpers;
using MashGamemodeLibrary.Player.Loadout;
using MashGamemodeLibrary.Player.Stats;
using MashGamemodeLibrary.Player.Team;
using MashGamemodeLibrary.Registry.Keyed;
using MashGamemodeLibrary.Registry.Typed;
using MashGamemodeLibrary.Util;
using MashGamemodeLibrary.Util.Timer;
using MashGamemodeLibrary.networking;
using MashGamemodeLibrary.networking.Compatiblity;
using MashGamemodeLibrary.networking.Control;
using MashGamemodeLibrary.networking.Validation;
using MashGamemodeLibrary.networking.Validation.Routes;
using MashGamemodeLibrary.networking.Variable;
using MashGamemodeLibrary.networking.Variable.Encoder;
using MashGamemodeLibrary.networking.Variable.Encoder.Impl;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using MoreItemsInDevTools.Patches;
using Spiderman;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "Mash's Gamemode Library", "1.0.0", "Mash", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "LabFusion" })]
[assembly: MelonOptionalDependencies(new string[] { "Spiderman" })]
[assembly: NetworkIdentifiable("MGL")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("MashGamemodeLibrary")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MashGamemodeLibrary")]
[assembly: AssemblyTitle("MashGamemodeLibrary")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace MashGamemodeLibrary
{
	public class Mod : MelonMod
	{
		public static readonly string ModDataDirectory = MelonEnvironment.UserDataDirectory + "/mashgamemodelibrary";

		public override void OnInitializeMelon()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			if (MelonBase.FindMelon("LabFusion", "Lakatrazz") != null)
			{
				ModIntegrations.TryInitialize();
				ModuleManager.RegisterModule<FusionModule>();
				RegisterInternal<Mod>();
				NetworkEventsExtender.Register();
				Hooking.OnWarehouseReady += OnWarehouseReady;
				MultiplayerHooking.OnTargetLevelLoaded += new UpdateEvent(Cleanup);
			}
		}

		public override void OnUpdate()
		{
			PlayerActionManager.Update();
			ConfigManager.Update();
			SpawnHelper.Update();
		}

		private void OnWarehouseReady()
		{
			AudioRegistry.RegisterAll();
		}

		private static void Cleanup()
		{
			InternalGamemodeManager.Reset();
			EcsManager.Reset();
			PlayerDataManager.Clear();
			PlayerGunManager.Reset();
			GamemodeCompatibilityChecker.ClearRemoteHashes();
		}

		private static void RegisterInternal<T>()
		{
			EcsManager.RegisterAll<T>();
			RemoteEventMessageHandler.RegisterMod<T>();
			AutoRegistry.Register<T>();
			PlayerData.Register<T>();
		}

		public static void Register<T>()
		{
			GamePhaseManager.Registry.RegisterAll<T>();
			LogicTeamManager.Registry.RegisterAll<T>();
			RegisterInternal<T>();
		}
	}
}
namespace MashGamemodeLibrary.Util
{
	[AttributeUsage(AttributeTargets.Class)]
	public class RequireStaticConstructor : Attribute
	{
	}
	public interface IGuaranteeStaticConstructor
	{
	}
	public static class AutoRegistry
	{
		private static bool HasField(Type type)
		{
			if (type.GetCustomAttribute<RequireStaticConstructor>() != null)
			{
				return true;
			}
			return (from fieldInfo in type.GetFields()
				select fieldInfo.FieldType).Any((Type fieldType) => typeof(IGuaranteeStaticConstructor).IsAssignableFrom(fieldType));
		}

		internal static void Register(Assembly assembly)
		{
			Type[] types = assembly.GetTypes();
			foreach (Type type in types)
			{
				if (HasField(type))
				{
					RuntimeHelpers.RunClassConstructor(type.TypeHandle);
				}
			}
		}

		internal static void Register<T>()
		{
			Register(typeof(T).Assembly);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field)]
	public class SerializableField : Attribute
	{
	}
	internal class FieldSerializer
	{
		private readonly FieldInfo _field;

		public FieldSerializer(FieldInfo field)
		{
			_field = field;
		}

		public void SerializeField(INetSerializer serializer, object instance)
		{
			object value = _field.GetValue(instance);
			NetSerializerExtensions.SerializeValue(serializer, ref value);
			if (serializer.IsReader)
			{
				_field.SetValue(instance, value);
			}
		}
	}
	public abstract class AutoSerialized<TValue> : INetSerializable where TValue : AutoSerialized<TValue>
	{
		private static readonly List<FieldSerializer> Serializables;

		static AutoSerialized()
		{
			Serializables = new List<FieldSerializer>();
			Type typeFromHandle = typeof(TValue);
			bool flag = typeFromHandle.GetCustomAttribute<SerializableField>() != null;
			FieldInfo[] fields = typeFromHandle.GetFields();
			foreach (FieldInfo fieldInfo in fields)
			{
				if (flag || fieldInfo.GetCustomAttribute<SerializableField>() != null)
				{
					Serializables.Add(new FieldSerializer(fieldInfo));
				}
			}
		}

		public void Serialize(INetSerializer serializer)
		{
			Serialize(serializer, (TValue)this);
		}

		public static void Serialize(INetSerializer serializer, TValue value)
		{
			foreach (FieldSerializer serializable in Serializables)
			{
				serializable.SerializeField(serializer, value);
			}
		}
	}
	public static class BonelabLayers
	{
		public const int Default = 0;

		public const int NoRaycast = 2;

		public const int Fixture = 7;

		public const int Player = 8;

		public const int NoCollide = 9;

		public const int Dynamic = 10;

		public const int EnemyColliders = 12;

		public const int Interactable = 15;

		public const int Deciverse = 17;

		public const int Socket = 18;

		public const int PlayerAndNpc = 21;

		public const int FeetOnly = 23;

		public const int Feet = 24;

		public const int EntityTrigger = 30;

		public const int BeingTrigger = 31;
	}
	public static class DictionaryExtender
	{
		public static TValue GetValueOrCreate<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TValue> factory) where TKey : notnull
		{
			if (dict.TryGetValue(key, out TValue value))
			{
				return value;
			}
			return dict[key] = factory();
		}

		public static TValue GetValueOrCreate<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) where TKey : notnull where TValue : new()
		{
			if (dict.TryGetValue(key, out TValue value))
			{
				return value;
			}
			return dict[key] = new TValue();
		}

		public static void Clear<TKey, TValue>(this Dictionary<TKey, TValue> dict, Action<KeyValuePair<TKey, TValue>> onEach) where TKey : notnull
		{
			IEnumerableExtensions.ForEach<KeyValuePair<TKey, TValue>>((IEnumerable<KeyValuePair<TKey, TValue>>)dict, onEach);
			dict.Clear();
		}

		public static void Clear<TKey, TValue>(this Dictionary<TKey, TValue> dict, Action<TKey, TValue> onEach) where TKey : notnull
		{
			Action<TKey, TValue> onEach2 = onEach;
			dict.Clear(delegate(KeyValuePair<TKey, TValue> kvp)
			{
				onEach2(kvp.Key, kvp.Value);
			});
		}
	}
	public class DummySerializable : INetSerializable
	{
		public int? GetSize()
		{
			return 0;
		}

		public void Serialize(INetSerializer serializer)
		{
		}
	}
	public static class GameObjectMemoryChecker
	{
		private struct MemoryBasicInformation
		{
			public IntPtr BaseAddress;

			public IntPtr AllocationBase;

			public uint AllocationProtect;

			public IntPtr RegionSize;

			public uint State;

			public uint Protect;

			public uint Type;
		}

		private const uint PageNoaccess = 1u;

		private const uint PageGuard = 256u;

		private const uint MemFree = 65536u;

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern IntPtr VirtualQuery(IntPtr lpAddress, out MemoryBasicInformation lpBuffer, IntPtr dwLength);

		public static bool IsPointerAccessible(IntPtr ptr)
		{
			if (ptr == IntPtr.Zero)
			{
				return false;
			}
			if (VirtualQuery(ptr, out var lpBuffer, new IntPtr(Marshal.SizeOf(typeof(MemoryBasicInformation)))) == IntPtr.Zero)
			{
				return false;
			}
			if ((lpBuffer.Protect & 1) == 0 && (lpBuffer.Protect & 0x100) == 0)
			{
				return lpBuffer.State != 65536;
			}
			return false;
		}
	}
	public static class GuidExtender
	{
		public static void Serialize(this ref Guid guid, INetSerializer serializer)
		{
			byte[] array = ArrayPool<byte>.Shared.Rent(16);
			if (serializer.IsReader)
			{
				serializer.SerializeValue(ref array);
				guid = new Guid(array);
			}
			else
			{
				guid.TryWriteBytes(array.AsSpan());
				serializer.SerializeValue(ref array);
			}
		}
	}
	public static class ImageHelper
	{
		public static Texture2D? LoadEmbeddedImage<T>(string resourceName)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			using Stream stream = typeof(T).Assembly.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				return null;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
			{
				name = resourceName,
				hideFlags = (HideFlags)32
			};
			if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array)))
			{
				return null;
			}
			val.Apply();
			return val;
		}
	}
	internal static class InternalLogger
	{
		[Conditional("DEBUG")]
		internal static void Debug(string txt)
		{
			MelonLogger.Msg("[Mash's Gamemode Library - DEBUG] " + txt);
		}

		public static void Error(string error)
		{
			MelonLogger.Error("[Mash's Gamemode Library - ERROR] " + error);
		}

		public static void Warn(string warning)
		{
			MelonLogger.Warning("[Mash's Gamemode Library - WARNING] " + warning);
		}
	}
	public static class MathUtil
	{
		public static float InverseLerp(float from, float to, float value)
		{
			if (from > to)
			{
				float num = to;
				float num2 = from;
				from = num;
				to = num2;
			}
			return (value - from) / (to - from);
		}

		public static float Lerp(float from, float to, float value)
		{
			if (from > to)
			{
				float num = to;
				float num2 = from;
				from = num;
				to = num2;
			}
			return from + value * (to - from);
		}

		public static float Clamp(float value, float min, float max)
		{
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}

		public static float Clamp01(this float value)
		{
			return Clamp(value, 0f, 1f);
		}
	}
	public static class StableHash
	{
		public static ulong Fnv1A64(string input)
		{
			ulong num = 14695981039346656037uL;
			foreach (char c in input)
			{
				num ^= c;
				num *= 1099511628211L;
			}
			return num;
		}

		public static ulong GetStableHash(this string input)
		{
			return Fnv1A64(input);
		}

		public static ulong GetStableHash(this Type type)
		{
			return Fnv1A64(type.AssemblyQualifiedName ?? type.FullName ?? type.Name);
		}

		public static ulong GetStableHash<T>(this T instance) where T : Enum
		{
			return Fnv1A64($"{typeof(T).Name}-{instance}");
		}
	}
}
namespace MashGamemodeLibrary.Util.Timer
{
	internal class TimeRemainingPacket : INetSerializable
	{
		public float TimeRemaining;

		public int? GetSize()
		{
			return 4;
		}

		public void Serialize(INetSerializer serializer)
		{
			serializer.SerializeValue(ref TimeRemaining);
		}
	}
	public static class CommonTimeMarkerEvents
	{
		private static readonly RemoteEvent<TimeRemainingPacket> TimeRemainingEvent = new RemoteEvent<TimeRemainingPacket>(OnTimeRemainingEvent, CommonNetworkRoutes.HostToAll);

		private static readonly string[] Ones = new string[10] { "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine" };

		private static readonly string[] Teens = new string[10] { "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen" };

		private static readonly string[] Tens = new string[7] { "", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty" };

		private static string ToText(int number)
		{
			if (number < 10)
			{
				return Ones[number];
			}
			if (number < 20)
			{
				return Teens[number - 10];
			}
			int num = number / 10;
			int num2 = number % 10;
			string text = Tens[num];
			if (num2 == 0)
			{
				return text;
			}
			return text + Ones[num2];
		}

		public static TimeMarker TimeRemaining(float time)
		{
			return new TimeMarker(MarkerType.BeforeEnd, time, delegate
			{
				Executor.RunIfHost(delegate
				{
					TimeRemainingEvent.Call(new TimeRemainingPacket
					{
						TimeRemaining = time
					});
				});
			});
		}

		private static void SendWarning(string text)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			Notifier.Send(new Notification
			{
				Title = NotificationText.op_Implicit(text),
				PopupLength = 3f,
				ShowPopup = true,
				SaveToMenu = false,
				Type = (NotificationType)1
			});
		}

		private static void OnTimeRemainingEvent(TimeRemainingPacket packet)
		{
			if (packet.TimeRemaining >= 60f)
			{
				SendWarning(ToText((int)MathF.Round(packet.TimeRemaining / 60f)) + " Minutes Left");
			}
			else
			{
				SendWarning(ToText((int)MathF.Round(packet.TimeRemaining)) + " Seconds Left");
			}
		}
	}
	public enum MarkerType
	{
		AfterStart,
		BeforeEnd,
		Interval
	}
	public class TimeMarker
	{
		public bool Hit;

		public Action<float> OnHit;

		public float Time;

		public MarkerType Type;

		public TimeMarker(MarkerType type, float time, Action<float> onHit)
		{
			Type = type;
			Time = time;
			OnHit = onHit;
		}
	}
	public class MarkableTimer
	{
		private bool _hitTimeout;

		private TimeMarker[] _markers;

		private float _timeout;

		private float _timer;

		public float Duration => _timeout;

		public event Action? OnReset;

		public event Action<float>? OnTimeout;

		public MarkableTimer(float timeout, params TimeMarker[] markers)
		{
			_timeout = timeout;
			_markers = markers;
		}

		private float GetActualTime(TimeMarker marker)
		{
			float time = marker.Time;
			return marker.Type switch
			{
				MarkerType.AfterStart => time, 
				MarkerType.BeforeEnd => _timeout - time, 
				_ => time, 
			};
		}

		private void HandleIntervalMarker(TimeMarker marker, float delta)
		{
			float num = _timer - delta;
			float time = marker.Time;
			float num2 = MathF.Floor(_timer / time);
			float num3 = MathF.Floor(num / time);
			if (MathF.Abs(num2 - num3) != 0f)
			{
				marker.OnHit(MathF.Floor(_timer));
			}
		}

		private void HandleOffsetMarker(TimeMarker marker)
		{
			float actualTime = GetActualTime(marker);
			if (_timer < actualTime)
			{
				marker.Hit = false;
			}
			else if (!marker.Hit)
			{
				marker.Hit = true;
				if (!(actualTime >= _timeout) && !(actualTime < 0f))
				{
					marker.OnHit(actualTime);
				}
			}
		}

		private void CheckMarker(float delta)
		{
			TimeMarker[] markers = _markers;
			foreach (TimeMarker timeMarker in markers)
			{
				MarkerType type = timeMarker.Type;
				if (type == MarkerType.AfterStart || type == MarkerType.BeforeEnd)
				{
					HandleOffsetMarker(timeMarker);
				}
				else
				{
					HandleIntervalMarker(timeMarker, delta);
				}
			}
		}

		public void Update(float delta)
		{
			if (!_hitTimeout)
			{
				_timer += delta;
				if (_timer > _timeout)
				{
					this.OnTimeout?.Invoke(_timeout);
					_hitTimeout = true;
				}
				else
				{
					CheckMarker(delta);
				}
			}
		}

		public void SetTimeout(float timeout)
		{
			_timeout = timeout;
			bool hitTimeout = _hitTimeout;
			_hitTimeout = _timer >= _timeout;
			if (!hitTimeout && _hitTimeout)
			{
				this.OnTimeout?.Invoke(_timeout);
			}
		}

		public bool HasReachedTimeout()
		{
			return _hitTimeout;
		}

		public float GetElapsedTime()
		{
			return _timer;
		}

		public void SetMarkers(params TimeMarker[] markers)
		{
			_markers = markers;
		}

		public void Reset()
		{
			if (_timer != 0f)
			{
				this.OnReset?.Invoke();
				TimeMarker[] markers = _markers;
				for (int i = 0; i < markers.Length; i++)
				{
					markers[i].Hit = false;
				}
			}
			_timer = 0f;
			_hitTimeout = false;
		}
	}
}
namespace MashGamemodeLibrary.Registry
{
	public interface IKeyable<in TKey>
	{
		ulong CreateID(Type type);

		ulong CreateID<T>() where T : notnull, TKey;

		ulong CreateID(TKey instance);

		ulong GetID<T>() where T : notnull, TKey
		{
			return this.CreateID<T>();
		}

		ulong GetID(Type type)
		{
			return CreateID(type);
		}

		ulong GetID(TKey instance)
		{
			return CreateID(instance);
		}
	}
}
namespace MashGamemodeLibrary.Registry.Typed
{
	public class FactoryTypedRegistry<TValue> : TypedRegistry<Func<TValue>, TValue> where TValue : class
	{
		private const int NullID = 0;

		protected override Func<TValue> Create<T>()
		{
			return () => (TValue)(object)new T();
		}

		protected override bool TryToValue(Func<TValue>? from, [MaybeNullWhen(false)] out TValue value)
		{
			value = ((from != null) ? from() : null);
			return value != null;
		}

		private void WriteValue(NetWriter writer, TValue? value)
		{
			if (value == null)
			{
				writer.Write(0);
				return;
			}
			ulong iD = GetID(value);
			writer.Write(iD);
			INetSerializable val = (INetSerializable)(object)((value is INetSerializable) ? value : null);
			if (val != null)
			{
				val.Serialize((INetSerializer)(object)writer);
			}
		}

		private void ReadValue(NetReader reader, ref TValue? value)
		{
			ulong num = reader.ReadUInt64();
			TValue value2;
			if (num == 0L)
			{
				value = null;
			}
			else if (!TryGet(num, out value2))
			{
				InternalLogger.Error($"Failed to read value with id {num} from registry {typeof(TValue).FullName}");
				value = null;
			}
			else
			{
				INetSerializable val = (INetSerializable)(object)((value2 is INetSerializable) ? value2 : null);
				if (val != null)
				{
					val.Serialize((INetSerializer)(object)reader);
				}
				value = value2;
			}
		}

		public void SerializeValue(INetSerializer serializer, ref TValue? value)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			if (serializer.IsReader)
			{
				ReadValue((NetReader)serializer, ref value);
			}
			else
			{
				WriteValue((NetWriter)serializer, value);
			}
		}
	}
	public interface ITypedRegistry<TValue> : IKeyable<TValue> where TValue : notnull
	{
		new ulong CreateID(Type type);

		void Register<T>() where T : TValue, new();

		void RegisterAll<T>();

		Type? GetType(ulong id);

		bool TryGetType(ulong id, [MaybeNullWhen(false)] out Type type);

		TValue? Get(ulong id);

		TValue? Get(Type type);

		T? Get<T>() where T : TValue;

		bool TryGet(ulong id, [MaybeNullWhen(false)] out TValue entry);

		bool TryGet(Type type, [MaybeNullWhen(false)] out TValue entry);

		bool TryGet<T>([MaybeNullWhen(false)] out T entry) where T : TValue;

		IEnumerable<Type> GetAllTypes();
	}
	public class SingletonTypedRegistry<TValue> : TypedRegistry<TValue, TValue> where TValue : notnull
	{
		public void Register<T>(T value) where T : TValue
		{
			ulong orCreateId = base.GetOrCreateId<T>();
			base.Register(orCreateId, value);
		}

		protected override TValue Create<T>()
		{
			return (TValue)(object)new T();
		}

		protected override bool TryToValue(TValue? from, [MaybeNullWhen(false)] out TValue value)
		{
			if (from == null)
			{
				value = default(TValue);
				return false;
			}
			value = from;
			return true;
		}
	}
	public abstract class TypedRegistry<TInternal, TValue> : KeyedRegistry<ulong, TInternal>, ITypedRegistry<TValue>, IKeyable<TValue> where TInternal : notnull where TValue : notnull
	{
		private readonly Dictionary<Type, ulong> _stableHashCache = new Dictionary<Type, ulong>();

		private readonly Dictionary<ulong, Type> _typeCache = new Dictionary<ulong, Type>();

		public ulong CreateID(Type type)
		{
			return type.GetStableHash();
		}

		public ulong CreateID<T>() where T : TValue
		{
			return CreateID(typeof(T));
		}

		public ulong CreateID(TValue instance)
		{
			return CreateID(instance.GetType());
		}

		public void Register<T>() where T : TValue, new()
		{
			ulong orCreateId = this.GetOrCreateId<T>();
			TInternal value = Create<T>();
			Register(orCreateId, value);
		}

		public void RegisterAll<T>()
		{
			Assembly assembly = typeof(T).Assembly;
			MethodInfo registerTypeMethod = GetType().GetMethod("Register", Type.EmptyTypes);
			if (registerTypeMethod == null)
			{
				throw new Exception("Could not find register method.");
			}
			IEnumerableExtensions.ForEach<Type>((from t in assembly.GetTypes()
				where typeof(TValue).IsAssignableFrom(t) && (object)t != null && t.IsClass && !t.IsAbstract && !t.IsInterface
				select t).Where(delegate(Type t)
			{
				if (t.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes) != null)
				{
					return true;
				}
				InternalLogger.Error("Type: " + t.Name + " has no default constructor. Ensure it satisfiers the \"new()\" clause.");
				return false;
			}), (Action<Type>)delegate(Type t)
			{
				registerTypeMethod.MakeGenericMethod(t).Invoke(this, null);
			});
		}

		public Type? GetType(ulong id)
		{
			return _typeCache.GetValueOrDefault(id);
		}

		public bool TryGetType(ulong id, [MaybeNullWhen(false)] out Type type)
		{
			return _typeCache.TryGetValue(id, out type);
		}

		public new TValue? Get(ulong id)
		{
			TryToValue(base.Get(id), out var value);
			return value;
		}

		public TValue? Get(Type type)
		{
			ulong iD = GetID(type);
			TryToValue(base.Get(iD), out var value);
			return value;
		}

		public virtual T Get<T>() where T : TValue
		{
			ulong iD = this.GetID<T>();
			TValue val = Get(iD);
			if (val is T)
			{
				return (T)(object)val;
			}
			return default(T);
		}

		public bool TryGet(ulong key, [MaybeNullWhen(false)] out TValue value)
		{
			if (!TryGet(key, out TInternal value2) || !TryToValue(value2, out var value3))
			{
				value = default(TValue);
				return false;
			}
			value = value3;
			return true;
		}

		public bool TryGet(Type type, [MaybeNullWhen(false)] out TValue entry)
		{
			ulong iD = GetID(type);
			return TryGet(iD, out entry);
		}

		public virtual bool TryGet<T>([MaybeNullWhen(false)] out T entry) where T : TValue
		{
			ulong iD = this.GetID<T>();
			if (!TryGet(iD, out var value))
			{
				entry = default(T);
				return false;
			}
			entry = (T)(object)value;
			return true;
		}

		public IEnumerable<Type> GetAllTypes()
		{
			return _typeCache.Values;
		}

		public IEnumerable<TValue> GetAll()
		{
			return _typeCache.Keys.Select((ulong k) => Get(k));
		}

		public ulong GetID(Type type)
		{
			if (!_stableHashCache.TryGetValue(type, out var value))
			{
				throw new Exception("Failed to get ID for unregistered type: " + type.FullName);
			}
			return value;
		}

		public ulong GetID<T>() where T : TValue
		{
			return GetID(typeof(T));
		}

		public ulong GetID(TValue instance)
		{
			return GetID(instance.GetType());
		}

		public ulong GetOrCreateId(Type type)
		{
			if (_stableHashCache.TryGetValue(type, out var value))
			{
				return value;
			}
			ulong num = CreateID(type);
			_stableHashCache[type] = num;
			_typeCache[num] = type;
			return num;
		}

		public ulong GetOrCreateId<T>() where T : TValue
		{
			return GetOrCreateId(typeof(T));
		}

		protected abstract TInternal Create<T>() where T : TValue, new();

		protected abstract bool TryToValue(TInternal? from, [MaybeNullWhen(false)] out TValue value);
	}
	public abstract class TypedRegistry<TValue> : TypedRegistry<TValue, TValue> where TValue : notnull
	{
	}
}
namespace MashGamemodeLibrary.Registry.Keyed
{
	public interface IKeyedRegistry<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IGuaranteeStaticConstructor where TKey : notnull where TValue : notnull
	{
		public delegate void OnRegisterHandler(TKey key, TValue value);

		event OnRegisterHandler? OnRegister;

		void Register<T>(TKey key, T value) where T : TValue;

		TValue? Get(TKey key);

		bool TryGet(TKey key, [MaybeNullWhen(false)] out TValue value);

		bool Contains(TKey key);
	}
	public class KeyedRegistry<TKey, TValue> : IKeyedRegistry<TKey, TValue>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IGuaranteeStaticConstructor where TKey : notnull where TValue : notnull
	{
		private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();

		public int Count => _dictionary.Count;

		public event IKeyedRegistry<TKey, TValue>.OnRegisterHandler? OnRegister;

		public void Register<T>(TKey id, T value) where T : TValue
		{
			_dictionary.Add(id, (TValue)(object)value);
			this.OnRegister?.Invoke(id, (TValue)(object)value);
		}

		public TValue? Get(TKey id)
		{
			return _dictionary.GetValueOrDefault(id);
		}

		public bool TryGet(TKey key, [MaybeNullWhen(false)] out TValue value)
		{
			return _dictionary.TryGetValue(key, out value);
		}

		public bool Contains(TKey id)
		{
			return _dictionary.ContainsKey(id);
		}

		public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
		{
			return _dictionary.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
}
namespace MashGamemodeLibrary.Registry.Generic
{
	public class RuntimeTypedRegistry : KeyedRegistry<ulong, object>, IKeyable<object>
	{
		private readonly Type RootType;

		public RuntimeTypedRegistry(Type rootType)
		{
			RootType = rootType;
		}

		public ulong CreateID(Type type)
		{
			return type.Name.GetStableHash();
		}

		public ulong CreateID<T>() where T : notnull
		{
			return CreateID(typeof(T));
		}

		public ulong CreateID(object instance)
		{
			return instance.GetType().Name.GetStableHash();
		}

		public void Register<T>(object value) where T : notnull
		{
			Type type = RootType.MakeGenericType(typeof(T));
			if (!value.GetType().IsAssignableFrom(type))
			{
				MelonLogger.Error("Failed to register: " + value.GetType().Name + ". Expected a value of: " + type.Name);
				return;
			}
			ulong id = CreateID<T>();
			Register(id, value);
		}

		public object? Get<T>() where T : notnull
		{
			ulong id = CreateID<T>();
			return Get(id);
		}
	}
}
namespace MashGamemodeLibrary.Loadout
{
	internal enum LoadCommandType
	{
		Weapon,
		Utility
	}
	internal enum WeaponType
	{
		Primary,
		Secondary,
		Tertiary,
		Utility
	}
	internal class FetchLoadoutPacket : INetSerializable
	{
		public string[] Barcodes;

		public LoadCommandType LoadCommandType;

		public void Serialize(INetSerializer serializer)
		{
			serializer.SerializeValue<LoadCommandType>(ref LoadCommandType);
			serializer.SerializeValue(ref Barcodes);
		}
	}
	public static class PalletLoadoutManager
	{
		private static readonly string[] PrimaryTypeTags = new string[3] { "SMG", "Shotgun", "Rifle" };

		private static readonly string[] SecondaryTypeTags = new string[1] { "Pistol" };

		private static readonly string[] TertiaryTypeTags = new string[2] { "Blade", "Blunt" };

		private static readonly RemoteEvent<FetchLoadoutPacket> FetchLoadoutEvent = new RemoteEvent<FetchLoadoutPacket>("FetchLoadoutEvent", OnFetchLoadout, CommonNetworkRoutes.HostToAll);

		private static readonly RemoteEvent<DummySerializable> AssignLoadoutEvent = new RemoteEvent<DummySerializable>("AssignLoadoutEvent", OnAssignLoadout, CommonNetworkRoutes.HostToAll);

		private static readonly Dictionary<WeaponType, List<Crate>> Items = new Dictionary<WeaponType, List<Crate>>();

		private static void ClearWeapons()
		{
			Items.GetValueOrDefault(WeaponType.Primary)?.Clear();
			Items.GetValueOrDefault(WeaponType.Secondary)?.Clear();
			Items.GetValueOrDefault(WeaponType.Tertiary)?.Clear();
		}

		private static List<Crate> GetCrateList(WeaponType type)
		{
			if (Items.TryGetValue(type, out List<Crate> value))
			{
				return value;
			}
			List<Crate> list = new List<Crate>();
			Items[type] = list;
			return list;
		}

		private static WeaponType? GetCrateType(Crate crate)
		{
			Enumerator<string> enumerator = crate._tags.GetEnumerator();
			while (enumerator.MoveNext())
			{
				string current = enumerator.Current;
				if (current != null)
				{
					if (PrimaryTypeTags.Contains(current))
					{
						return WeaponType.Primary;
					}
					if (SecondaryTypeTags.Contains(current))
					{
						return WeaponType.Secondary;
					}
					if (TertiaryTypeTags.Contains(current))
					{
						return WeaponType.Tertiary;
					}
				}
			}
			return null;
		}

		public static void LoadLocal(IEnumerable<string> barcodes)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_00a1: 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_00ca: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			ClearWeapons();
			Pallet pallet2 = default(Pallet);
			foreach (string barcode in barcodes)
			{
				Barcode val = new Barcode(barcode);
				if (ModBlacklist.IsBlacklisted(barcode) || GlobalModBlacklistManager.IsBarcodeBlacklisted(barcode))
				{
					MelonLogger.Error("Failed to load pallet with barcode: " + barcode + ": Mod is blacklisted");
					continue;
				}
				if (AssetWarehouse.Instance.TryGetPallet(val, ref pallet2))
				{
					AddPallet(pallet2);
					continue;
				}
				MelonLogger.Error("Failed to load pallet with barcode: " + barcode + ": Pallet not found");
				if (!ClientSettings.Downloading.DownloadSpawnables.Value)
				{
					break;
				}
				long value = DataConversions.ConvertMegabytesToBytes((long)ClientSettings.Downloading.MaxFileSize.Value);
				ModInstallInfo val2 = default(ModInstallInfo);
				val2.Target = 0;
				val2.Barcode = barcode;
				val2.FinishDownloadCallback = new DownloadCallback(OnModDownloaded);
				val2.MaxBytes = value;
				NetworkModRequester.RequestAndInstallMod(val2);
			}
			static void AddPallet(Pallet pallet)
			{
				Enumerator<Crate> enumerator2 = pallet.Crates.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					Crate current2 = enumerator2.Current;
					if (!((Scannable)current2)._redacted)
					{
						WeaponType? crateType = GetCrateType(current2);
						if (crateType.HasValue)
						{
							GetCrateList(crateType.Value).Add(current2);
						}
					}
				}
			}
			static void OnModDownloaded(DownloadCallbackInfo info)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				if ((int)info.Result != 2)
				{
					InternalLogger.Warn("Failed downloading spawnable!");
				}
				else
				{
					AddPallet(info.Pallet);
				}
			}
		}

		public static void LoadLocalUtility(IEnumerable<string> barcodes)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			List<Crate> crateList = GetCrateList(WeaponType.Utility);
			crateList.Clear();
			Crate item = default(Crate);
			foreach (string barcode in barcodes)
			{
				if (!AssetWarehouse.Instance.TryGetCrate(new Barcode(barcode), ref item))
				{
					MelonLogger.Error("Failed to load crate with barcode: " + barcode + ": Crate not found");
				}
				else
				{
					crateList.Add(item);
				}
			}
		}

		private static Barcode? Get(WeaponType type)
		{
			if (!Items.TryGetValue(type, out List<Crate> value))
			{
				return null;
			}
			if (value.Count == 0)
			{
				return null;
			}
			return ((Scannable)IEnumerableExtensions.GetRandom<Crate>((IEnumerable<Crate>)value)).Barcode;
		}

		public static MashGamemodeLibrary.Player.Loadout.Loadout GetLoadout()
		{
			Barcode barcode = Get(WeaponType.Primary);
			Barcode barcode2 = Get(WeaponType.Secondary);
			Barcode barcode3 = Get(WeaponType.Tertiary);
			Barcode barcode4 = Get(WeaponType.Utility);
			return new MashGamemodeLibrary.Player.Loadout.Loadout().SetSlotBarcode(SlotType.RightBack, barcode).SetSlotBarcode(SlotType.RightHolster, barcode2).SetSlotBarcode(SlotType.LeftBack, barcode4)
				.SetSlotBarcode(SlotType.Belt, barcode3);
		}

		public static void Load(string barcode)
		{
			Load(new string[1] { barcode });
		}

		public static void Load(IEnumerable<string> barcodes)
		{
			FetchLoadoutEvent.Call(new FetchLoadoutPacket
			{
				LoadCommandType = LoadCommandType.Weapon,
				Barcodes = barcodes.ToArray()
			});
		}

		public static void LoadUtility(IEnumerable<string> barcodes)
		{
			FetchLoadoutEvent.Call(new FetchLoadoutPacket
			{
				LoadCommandType = LoadCommandType.Utility,
				Barcodes = barcodes.ToArray()
			});
		}

		public static void AssignAll()
		{
			AssignLoadoutEvent.Call(new DummySerializable());
		}

		public static void ReassignOwnLoadout()
		{
			SlotData.ClearSpawned();
			GetLoadout().Assign();
		}

		private static void OnFetchLoadout(FetchLoadoutPacket packet)
		{
			switch (packet.LoadCommandType)
			{
			case LoadCommandType.Weapon:
				LoadLocal(packet.Barcodes);
				break;
			case LoadCommandType.Utility:
				LoadLocalUtility(packet.Barcodes);
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		private static void OnAssignLoadout(DummySerializable _)
		{
			ReassignOwnLoadout();
		}
	}
	public enum SlotType
	{
		LeftHolster,
		RightHolster,
		LeftBack,
		RightBack,
		Belt
	}
	public class SlotData
	{
		private static readonly HashSet<Poolee> SpawnedGuns = new HashSet<Poolee>();

		public Barcode? Barcode;

		public SlotData()
		{
		}

		public SlotData(Barcode? barcode)
		{
			Barcode = barcode;
		}

		public static string GetSlotName(SlotType type)
		{
			return type switch
			{
				SlotType.LeftHolster => "SideLf", 
				SlotType.RightHolster => "SideRt", 
				SlotType.LeftBack => "BackLf", 
				SlotType.RightBack => "BackRt", 
				SlotType.Belt => "BackCt", 
				_ => throw new ArgumentOutOfRangeException("type", type, null), 
			};
		}

		public void AssignSlot(RigManager rig, SlotType slotType)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			string slotName = GetSlotName(slotType);
			SlotContainer val = ((IEnumerable<SlotContainer>)rig.inventory.bodySlots).FirstOrDefault((Func<SlotContainer, bool>)((SlotContainer e) => ((Object)e).name.Equals(slotName)));
			InventorySlotReceiver slot = ((val != null) ? val.inventorySlotReceiver : null);
			if (slot == null)
			{
				return;
			}
			WeaponSlot slottedWeapon = slot._slottedWeapon;
			object obj;
			if (slottedWeapon == null)
			{
				obj = null;
			}
			else
			{
				Grip grip = slottedWeapon.grip;
				if (grip == null)
				{
					obj = null;
				}
				else
				{
					MarrowEntity marrowEntity2 = grip._marrowEntity;
					obj = ((marrowEntity2 != null) ? marrowEntity2._poolee : null);
				}
			}
			Poolee val2 = (Poolee)obj;
			if ((Object)(object)val2 != (Object)null)
			{
				val2.Despawn();
			}
			if (Barcode == (Barcode)null)
			{
				return;
			}
			Spawnable spawnable = new Spawnable
			{
				crateRef = new SpawnableCrateReference(Barcode),
				policyData = null
			};
			Transform transform = ((Component)slot).transform;
			SpawnRequestInfo val3 = default(SpawnRequestInfo);
			val3.Spawnable = spawnable;
			val3.Position = transform.position;
			val3.Rotation = transform.rotation;
			val3.SpawnEffect = false;
			val3.SpawnCallback = delegate(SpawnCallbackInfo info)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				info.WaitOnMarrowEntity(delegate(NetworkEntity networkEntity, MarrowEntity marrowEntity)
				{
					NetworkEntity networkEntity2 = networkEntity;
					SpawnedGuns.Add(marrowEntity._poolee);
					DelayUtilities.InvokeDelayed((Action)delegate
					{
						WeaponSlotExtender extender = networkEntity2.GetExtender<WeaponSlotExtender>();
						if (extender != null)
						{
							WeaponSlot component = ((EntityComponentExtender<WeaponSlot>)(object)extender).Component;
							if (!((Object)(object)component == (Object)null) && !((Object)(object)component.interactableHost == (Object)null) && !((EntityComponentExtender<WeaponSlot>)(object)extender).Component.interactableHost.IsAttached)
							{
								((InventoryHandReceiver)slot).OnHandDrop(((Il2CppObjectBase)component.interactableHost).TryCast<IGrippable>());
							}
						}
					}, 60);
				});
			};
			NetworkAssetSpawner.Spawn(val3);
		}

		public static void ClearSpawned()
		{
			foreach (Poolee spawnedGun in SpawnedGuns)
			{
				if (!((Object)(object)spawnedGun == (Object)null) && ((Behaviour)spawnedGun).isActiveAndEnabled)
				{
					spawnedGun.Despawn();
				}
			}
			SpawnedGuns.Clear();
		}
	}
	public class SpawnableElementData : FunctionElementData
	{
		private SpawnableCrateReference? _spawnable;

		public Action<Barcode> OnSetSpawnable = delegate
		{
		};

		public SpawnableElementData()
		{
			base.OnPressed = OnPressedInternal;
		}

		private static Barcode? GetHeldSpawnableBarcode(Hand hand)
		{
			if (!hand.HasAttachedObject())
			{
				return null;
			}
			Poolee componentInParent = ((Component)hand.AttachedReceiver).gameObject.GetComponentInParent<Poolee>();
			if (Object.op_Implicit((Object)(object)componentInParent))
			{
				return ((Scannable)componentInParent.SpawnableCrate)._barcode;
			}
			return null;
		}

		private static Barcode? GetHeldSpawnableBarcode()
		{
			return ((IEnumerable<Hand>)(object)new Hand[2]
			{
				Player.LeftHand,
				Player.RightHand
			}).Select(GetHeldSpawnableBarcode).OfType<Barcode>().FirstOrDefault();
		}

		private void OnPressedInternal()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Barcode heldSpawnableBarcode = GetHeldSpawnableBarcode();
			if (!(heldSpawnableBarcode == (Barcode)null))
			{
				_spawnable = new SpawnableCrateReference(heldSpawnableBarcode);
				OnSetSpawnable(((ScannableReference)_spawnable)._barcode);
			}
		}
	}
}
namespace MashGamemodeLibrary.Player
{
	public struct AvatarStats : INetSerializable
	{
		public float Vitality;

		public float Speed;

		public float UpperStrength;

		public float Agility;

		public float LowerStrength;

		public void Serialize(INetSerializer serializer)
		{
			serializer.SerializeValue(ref Vitality);
			serializer.SerializeValue(ref Speed);
			serializer.SerializeValue(ref UpperStrength);
			serializer.SerializeValue(ref Agility);
			serializer.SerializeValue(ref LowerStrength);
		}

		public readonly AvatarStats MultiplyHealth(float mult)
		{
			AvatarStats result = this;
			result.Vitality = Vitality * mult;
			return result;
		}
	}
}
namespace MashGamemodeLibrary.Player.Team
{
	[RequireStaticConstructor]
	public static class LogicTeamManager
	{
		private static readonly HashSet<ulong> EnabledTeams;

		public static readonly FactoryTypedRegistry<LogicTeam> Registry;

		private static readonly SyncedDictionary<byte, LogicTeam> AssignedTeams;

		static LogicTeamManager()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			EnabledTeams = new HashSet<ulong>();
			Registry = new FactoryTypedRegistry<LogicTeam>();
			AssignedTeams = new SyncedDictionary<byte, LogicTeam>("sync.AssignedTeams", new ByteEncoder(), new DynamicInstanceEncoder<LogicTeam>(Registry));
			AssignedTeams.OnValueAdded += OnAssigned;
			AssignedTeams.OnValueRemoved += OnRemoved;
			MultiplayerHooking.OnPlayerLeft += new PlayerUpdate(OnPlayerLeave);
		}

		private static ulong GetTeamID(Type type)
		{
			return Registry.GetOrCreateId(type);
		}

		public static ulong GetTeamID<T>() where T : LogicTeam
		{
			return GetTeamID(typeof(T));
		}

		public static void Enable<T>() where T : LogicTeam
		{
			ulong teamID = GetTeamID<T>();
			EnabledTeams.Add(teamID);
		}

		public static void Disable()
		{
			EnabledTeams.Clear();
			Executor.RunIfHost(delegate
			{
				AssignedTeams.Clear();
			});
		}

		public static ulong? GetLocalTeamID()
		{
			byte localSmallID = PlayerIDManager.LocalSmallID;
			if (!AssignedTeams.TryGetValue(localSmallID, out LogicTeam value))
			{
				return null;
			}
			return Registry.CreateID(value);
		}

		public static LogicTeam? GetLocalTeam()
		{
			byte localSmallID = PlayerIDManager.LocalSmallID;
			return AssignedTeams.GetValueOrDefault(localSmallID);
		}

		public static bool IsTeam<T>(this PlayerID playerID) where T : LogicTeam
		{
			if (AssignedTeams.TryGetValue(PlayerID.op_Implicit(playerID), out LogicTeam value))
			{
				return value.GetType() == typeof(T);
			}
			return false;
		}

		public static bool IsTeam(this PlayerID playerID, ulong teamID)
		{
			if (AssignedTeams.TryGetValue(PlayerID.op_Implicit(playerID), out LogicTeam value))
			{
				return Registry.CreateID(value) == teamID;
			}
			return false;
		}

		public static bool IsLocalTeam<T>() where T : LogicTeam
		{
			return PlayerIDManager.LocalID.IsTeam<T>();
		}

		public static ulong? GetPlayerTeamID(PlayerID player)
		{
			if (!AssignedTeams.TryGetValue(PlayerID.op_Implicit(player), out LogicTeam value))
			{
				return null;
			}
			return Registry.CreateID(value);
		}

		public static LogicTeam? GetPlayerTeam(PlayerID player)
		{
			return AssignedTeams.GetValueOrDefault(PlayerID.op_Implicit(player));
		}

		public static bool IsTeamMember(this PlayerID player)
		{
			LogicTeam localTeam = GetLocalTeam();
			LogicTeam playerTeam = GetPlayerTeam(player);
			if (localTeam == null || playerTeam == null)
			{
				return false;
			}
			return localTeam.GetType() == playerTeam.GetType();
		}

		public static void Assign<T>(this NetworkPlayer player, T team) where T : LogicTeam
		{
			NetworkPlayer player2 = player;
			T team2 = team;
			Executor.RunIfHost(delegate
			{
				AssignedTeams[PlayerID.op_Implicit(player2.PlayerID)] = team2;
			});
		}

		public static void Assign<T>(this PlayerID playerID) where T : LogicTeam
		{
			PlayerID playerID2 = playerID;
			Executor.RunIfHost(delegate
			{
				if (!Registry.TryGet<T>(out var entry))
				{
					MelonLogger.Error("Failed to assign team: " + typeof(T).Name + ". Team was not registered");
				}
				else
				{
					AssignedTeams[PlayerID.op_Implicit(playerID2)] = entry;
				}
			}, "Assigning teams");
		}

		public static void Assign(this PlayerID playerID, ulong teamID)
		{
			PlayerID playerID2 = playerID;
			Executor.RunIfHost(delegate
			{
				if (!Registry.TryGet(teamID, out LogicTeam value))
				{
					MelonLogger.Error($"Failed to assign team: {teamID}. Team was not registered");
				}
				else
				{
					AssignedTeams[PlayerID.op_Implicit(playerID2)] = value;
				}
			});
		}

		public static void AssignAllRandom()
		{
			Executor.RunIfHost(delegate
			{
				int num = Random.Range(0, 2);
				List<LogicTeam> list = EnabledTeams.Select((ulong id) => Registry.Get(id)).OfType<LogicTeam>().ToList();
				foreach (NetworkPlayer player in NetworkPlayer.Players)
				{
					LogicTeam value = list[num];
					AssignedTeams[PlayerID.op_Implicit(player.PlayerID)] = value;
					num = (num + 1) % EnabledTeams.Count;
				}
			});
		}

		public static void AssignAll<T>() where T : LogicTeam
		{
			Executor.RunIfHost(delegate
			{
				if (!Registry.TryGet<T>(out var entry))
				{
					MelonLogger.Error("Failed to assign all teams. " + typeof(T).Name + " is not registered.");
					return;
				}
				foreach (NetworkPlayer player in NetworkPlayer.Players)
				{
					AssignedTeams[PlayerID.op_Implicit(player.PlayerID)] = entry;
				}
			});
		}

		public static void AssignToSmallest(this PlayerID playerID)
		{
			PlayerID playerID2 = playerID;
			Executor.RunIfHost(delegate
			{
				if (EnabledTeams.Count != 0)
				{
					Dictionary<ulong, int> dictionary = new Dictionary<ulong, int>();
					foreach (ulong enabledTeam in EnabledTeams)
					{
						if (Registry.TryGetType(enabledTeam, out Type type))
						{
							dictionary[enabledTeam] = AssignedTeams.Count<KeyValuePair<byte, LogicTeam>>((KeyValuePair<byte, LogicTeam> kv) => kv.Value.GetType() == type);
						}
					}
					KeyValuePair<ulong, int> keyValuePair = dictionary.DefaultIfEmpty().MinBy((KeyValuePair<ulong, int> kv) => kv.Value);
					LogicTeam value = Registry.Get(keyValuePair.Key);
					AssignedTeams[PlayerID.op_Implicit(playerID2)] = value;
				}
			});
		}

		public static void AssignRandom<T>(IRandomProvider<PlayerID>? provider = null) where T : LogicTeam
		{
			if (provider == null)
			{
				provider = new BasicRandomProvider<PlayerID>(() => (from p in NetworkPlayer.Players
					where p.HasRig
					select p.PlayerID).ToList());
			}
			PlayerID randomValue = provider.GetRandomValue();
			if (randomValue == null)
			{
				MelonLogger.Error("Failed to select a player to assign to team: " + typeof(T).Name);
			}
			else
			{
				randomValue.Assign<T>();
			}
		}

		private static void OnAssigned(byte smallID, LogicTeam team)
		{
			NetworkPlayer val = default(NetworkPlayer);
			if (!NetworkPlayerManager.TryGetPlayer(smallID, ref val))
			{
				MelonLogger.Error($"Failed to assign player of id {smallID} to {team.Name}");
				return;
			}
			team.Assign(val);
			PlayerDataManager.CallEventOnAll(new TeamChangedEvent(val.PlayerID, team));
			GamePhase phase = GamePhaseManager.ActivePhase;
			if (phase != null)
			{
				team.Try(delegate(LogicTeam t)
				{
					t.OnPhaseChanged(phase);
				});
			}
		}

		private static void OnRemoved(byte smallID, LogicTeam team)
		{
			team.Remove();
			NetworkPlayer val = default(NetworkPlayer);
			if (NetworkPlayerManager.TryGetPlayer(smallID, ref val))
			{
				PlayerDataManager.CallEventOnAll(new TeamChangedEvent(val.PlayerID, null));
			}
		}

		public static void OnPhaseChanged(GamePhase activePhase)
		{
			GamePhase activePhase2 = activePhase;
			foreach (LogicTeam value in AssignedTeams.Values)
			{
				value.Try(delegate(LogicTeam t)
				{
					t.OnPhaseChanged(activePhase2);
				});
			}
		}

		private static void OnPlayerLeave(PlayerID playerId)
		{
			AssignedTeams.Remove(playerId.SmallID);
		}
	}
	public enum TeamStatisticKeys
	{
		RoundsWon
	}
	[RequireStaticConstructor]
	public static class PersistentTeams
	{
		private static readonly RemoteEvent WinMessageEvent = new RemoteEvent("PersistentTeams_WinMessage", OnWinMessage, CommonNetworkRoutes.HostToAll);

		private static readonly SyncedDictionary<byte, int> PlayerTeamIndices = new SyncedDictionary<byte, int>("PersistentTeams_PlayerTeamIndices", new ByteEncoder(), new IntEncoder());

		private static readonly SyncedDictionary<int, int> TeamScores = new SyncedDictionary<int, int>("PersistentTeams_TeamScores", new IntEncoder(), new IntEncoder());

		private static readonly HashSet<PlayerID> LateJoinerQueue = new HashSet<PlayerID>();

		private static readonly List<ulong> TeamIds = new List<ulong>();

		private static int _shift = Random.RandomRangeInt(0, 2);

		private static ulong GetTeamId(int setIndex)
		{
			int index = (setIndex + _shift) % TeamIds.Count;
			return TeamIds[index];
		}

		public static void AddTeamID(ulong id)
		{
			TeamIds.Add(id);
		}

		public static void AddTeam<T>() where T : LogicTeam
		{
			AddTeamID(LogicTeamManager.Registry.CreateID<T>());
		}

		private static void Assign(PlayerID playerID, int index)
		{
			if (!PlayerTeamIndices.ContainsKey(PlayerID.op_Implicit(playerID)))
			{
				PlayerTeamIndices[PlayerID.op_Implicit(playerID)] = index;
			}
		}

		public static void AddPlayers(IEnumerable<PlayerID> playerIds)
		{
			int num = 0;
			foreach (PlayerID item in playerIds.Shuffle())
			{
				Assign(item, num);
				num = (num + 1) % TeamIds.Count;
			}
		}

		public static void OverwritePlayers(IEnumerable<PlayerID> playerIds)
		{
			PlayerTeamIndices.Clear();
			AddPlayers(playerIds);
		}

		public static void OverwritePlayers(IEnumerable<IEnumerable<PlayerID>> teamPlayerIds)
		{
			PlayerTeamIndices.Clear();
			int num = 0;
			foreach (IEnumerable<PlayerID> teamPlayerId in teamPlayerIds)
			{
				foreach (PlayerID item in teamPlayerId)
				{
					Assign(item, num);
				}
				num = (num + 1) % TeamIds.Count;
			}
		}

		public static void RandomizeShift()
		{
			_shift += Random.RandomRangeInt(0, TeamIds.Count);
		}

		public static void QueueLateJoiner(PlayerID playerID)
		{
			LateJoinerQueue.Add(playerID);
		}

		public static void AssignAll()
		{
			if (PlayerTeamIndices.Count == 0)
			{
				MelonLogger.Error("No valid set found.");
				return;
			}
			Dictionary<int, int> dictionary = (from p in PlayerTeamIndices
				select p.Value into i
				group i by i).ToDictionary((IGrouping<int, int> g) => g.Key, (IGrouping<int, int> g) => g.Count());
			NetworkPlayer val = default(NetworkPlayer);
			int value;
			foreach (PlayerID item in LateJoinerQueue)
			{
				if (!item.IsValid)
				{
					LateJoinerQueue.Remove(item);
				}
				else if (NetworkPlayerManager.TryGetPlayer(PlayerID.op_Implicit(item), ref val) && val.HasRig)
				{
					LateJoinerQueue.Remove(item);
					int key = dictionary.MinBy((KeyValuePair<int, int> t) => t.Value).Key;
					Assign(item, key);
					Dictionary<int, int> dictionary2 = dictionary;
					value = key;
					dictionary2[value]++;
				}
			}
			_shift++;
			foreach (KeyValuePair<byte, int> playerTeamIndex in PlayerTeamIndices)
			{
				playerTeamIndex.Deconstruct(out var key2, out value);
				byte num = key2;
				int setIndex = value;
				PlayerID playerID = PlayerIDManager.GetPlayerID(num);
				if (!playerID.IsValid)
				{
					break;
				}
				playerID.Assign(GetTeamId(setIndex));
			}
		}

		public static void AddScore(ulong teamId, int score)
		{
			int num = (TeamIds.IndexOf(teamId) - _shift) % TeamIds.Count;
			if (num < 0)
			{
				num += TeamIds.Count;
			}
			int valueOrDefault = TeamScores.GetValueOrDefault(num, 0);
			TeamScores[num] = valueOrDefault + score;
		}

		public static void Clear()
		{
			_shift = 0;
			TeamIds.Clear();
			PlayerTeamIndices.Clear();
			TeamScores.Clear();
		}

		public static int GetTeamIndex(PlayerID playerID)
		{
			if (!PlayerTeamIndices.TryGetValue(PlayerID.op_Implicit(playerID), out var value))
			{
				return -1;
			}
			return value;
		}

		public static int GetTeamScore(int teamIndex)
		{
			if (!TeamScores.TryGetValue(teamIndex, out var value))
			{
				return 0;
			}
			return value;
		}

		public static int GetPlayerTeamScore(PlayerID playerID)
		{
			return GetTeamScore(GetTeamIndex(playerID));
		}

		public static void SendMessage()
		{
			if (PlayerTeamIndices.Count != 0)
			{
				WinMessageEvent.Call();
			}
		}

		private static void OnWinMessage(byte senderId)
		{
			//IL_015c: 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_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			List<(string, int)> list = new List<(string, int)>(2);
			List<(int, int)> list2 = (from kvp in TeamScores
				select (kvp.Key, kvp.Value) into p
				orderby p.score descending
				select p).Take(2).ToList();
			if (list2.Count == 0)
			{
				return;
			}
			NetworkPlayer val = default(NetworkPlayer);
			foreach (var item3 in list2)
			{
				int teamID = item3.Item1;
				int item = item3.Item2;
				string item2 = (NetworkPlayerManager.TryGetPlayer(PlayerTeamIndices.FirstOrDefault((KeyValuePair<byte, int> p) => p.Value == teamID).Key, ref val) ? val.Username : "Unknown");
				list.Add((item2, item));
			}
			int num = PlayerTeamIndices[PlayerIDManager.LocalSmallID];
			bool flag = list2.First().Item1 == num;
			string text = (flag ? "Victory!" : "Defeat!");
			string text2 = string.Join("\n", list.Select(((string, int) f) => $"{f.Item1}'s Team: {f.Item2} points"));
			Notifier.Send(new Notification
			{
				Title = NotificationText.op_Implicit(text),
				Message = NotificationText.op_Implicit(text2),
				PopupLength = 6f,
				SaveToMenu = true,
				ShowPopup = true,
				Type = (NotificationType)(flag ? 3 : 2)
			});
			PlayerStatisticsTracker.AwardBits();
		}
	}
	public abstract class LogicTeam
	{
		private NetworkPlayer? _owner;

		public abstract string Name { get; }

		public virtual Texture? Icon => null;

		public NetworkPlayer Owner => _owner ?? throw new InvalidOperationException("No player is currently assigned to team: " + Name + "!");

		protected virtual void OnAssigned()
		{
		}

		public virtual void OnPhaseChanged(GamePhase phase)
		{
		}

		protected virtual void OnRemoved()
		{
		}

		internal void Assign(NetworkPlayer player)
		{
			if (LobbyInfoManager.LobbyInfo.NameTags)
			{
				player.Icon.Texture = Icon;
				player.Icon.Visible = (Object)(object)Icon != (Object)null;
			}
			_owner = player;
			Executor.RunChecked<Action>(OnAssigned);
		}

		internal void Remove()
		{
			if (_owner != null)
			{
				Owner.Icon.Texture = null;
				Owner.Icon.Visible = false;
				Executor.RunChecked<Action>(OnRemoved);
			}
		}
	}
}
namespace MashGamemodeLibrary.Player.Stats
{
	public static class AvatarStatManager
	{
		private static AvatarStats? _localStatOverride;

		private const float TargetHeight = 1.8f;

		private const float SafeMargin = 0.2f;

		private const float MaxMargin = 0.8f;

		private const float Multiplier = 0.5f;

		private const float TeamUnbalancedSteps = 1f;

		private const float TeamUnbalancedMultiplier = 0.5f;

		public static bool BalanceStats { get; set; }

		private static void SetVitality(float? value)
		{
			if (SpectatorExtender.IsLocalPlayerSpectating())
			{
				value = 100f;
			}
			if (!LocalHealth.VitalityOverride.Equals(value))
			{
				LocalHealth.VitalityOverride = value;
			}
		}

		public static void RefreshVitality()
		{
			SetVitality(GetLocalStats(Player.Avatar)?.Vitality);
		}

		public static void SetAvatarAndStats(string barcode, AvatarStats stats)
		{
			_localStatOverride = stats;
			SetVitality(stats.Vitality);
			LocalAvatar.AvatarOverride = barcode;
		}

		public static void SetStats(AvatarStats stats)
		{
			_localStatOverride = stats;
			SetVitality(stats.Vitality);
			LocalAvatar.RefreshAvatar();
		}

		public static void ResetStats()
		{
			_localStatOverride = null;
			SetVitality(null);
			LocalAvatar.RefreshAvatar();
		}

		private static float GetBalancedModifier(Avatar avatar)
		{
			float num = Mathf.Abs(avatar.height - 1.8f);
			if (num <= 0.2f)
			{
				return 1f;
			}
			if (num >= 0.8f)
			{
				return 0.5f;
			}
			float num2 = (num - 0.2f) / 0.6f;
			return 1f - num2 * 0.5f;
		}

		private static float GetTeamBalanceModifier()
		{
			ulong? localTeamId = LogicTeamManager.GetLocalTeamID();
			if (!localTeamId.HasValue)
			{
				return 1f;
			}
			List<NetworkPlayer> list = NetworkPlayer.Players.Where((NetworkPlayer p) => p.HasRig).ToList();
			int num = list.Count((NetworkPlayer p) => LogicTeamManager.GetPlayerTeamID(p.PlayerID) == localTeamId.Value);
			int num2 = list.Count - num;
			if (num2 <= num)
			{
				return 1f;
			}
			int num3 = num2 - num;
			if ((float)num3 >= 1f)
			{
				return 1.5f;
			}
			float num4 = (float)num3 / 1f;
			return 1f + num4 * 0.5f;
		}

		public static bool TryGetLocalStats(Avatar? avatar, out AvatarStats stats)
		{
			if (!_localStatOverride.HasValue)
			{
				stats = default(AvatarStats);
				return false;
			}
			if (BalanceStats)
			{
				float num = (((Object)(object)avatar != (Object)null) ? GetBalancedModifier(avatar) : 1f);
				float teamBalanceModifier = GetTeamBalanceModifier();
				stats = _localStatOverride.Value.MultiplyHealth(num * teamBalanceModifier);
			}
			else
			{
				stats = _localStatOverride.Value;
			}
			return true;
		}

		public static AvatarStats? GetLocalStats(Avatar? avatar)
		{
			if (!TryGetLocalStats(avatar, out var stats))
			{
				return null;
			}
			return stats;
		}
	}
}
namespace MashGamemodeLibrary.Player.Spawning
{
	public record struct AvoidSpawningNear
	{
		internal float Radius { get; }

		internal float RadiusSquare { get; }

		public Vector3 Position;

		public AvoidSpawningNear(Vector3 position, float radius)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Position = position;
			Radius = radius;
			RadiusSquare = Mathf.Pow(radius, 2f);
		}

		[CompilerGenerated]
		private readonly bool PrintMembers(StringBuilder builder)
		{
			builder.Append("Position = ");
			builder.Append(((object)(Vector3)(ref Position)).ToString());
			return true;
		}

		[CompilerGenerated]
		public override readonly int GetHashCode()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return (EqualityComparer<Vector3>.Default.GetHashCode(Position) * -1521134295 + EqualityComparer<float>.Default.GetHashCode(Radius)) * -1521134295 + EqualityComparer<float>.Default.GetHashCode(RadiusSquare);
		}

		[CompilerGenerated]
		public readonly bool Equals(AvoidSpawningNear other)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (EqualityComparer<Vector3>.Default.Equals(Position, other.Position) && EqualityComparer<float>.Default.Equals(Radius, other.Radius))
			{
				return EqualityComparer<float>.Default.Equals(RadiusSquare, other.RadiusSquare);
			}
			return false;
		}
	}
	public static class DynamicSpawnCollector
	{
		private const float SafeRadius = 4f;

		private const int StaticLayer = 13;

		private const int DefaultLayer = 0;

		private static GameObject? _spawnGameObject;

		private static Vector3 _center = Vector3.zero;

		private static float _radius;

		private static NavMeshData? _navMeshData;

		private static List<Vector3> _validSpawnPoints = new List<Vector3>();

		private static void SetSpawn(Vector3 position)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			if ((Object)(object)_spawnGameObject == (Object)null)
			{
				_spawnGameObject = new GameObject();
			}
			_spawnGameObject.transform.position = position;
			FusionPlayer.SetSpawnPoints((Transform[])(object)new Transform[1] { _spawnGameObject.transform });
		}

		public static void CollectAt(Vector3 center, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			_center = center;
			_radius = radius;
			Bounds val = default(Bounds);
			((Bounds)(ref val))..ctor(center, Vector3.one * (radius * 2f));
			List<NavMeshBuildSource> val2 = new List<NavMeshBuildSource>();
			NavMeshBuilder.CollectSources(val, 8193, (NavMeshCollectGeometry)1, 0, new List<NavMeshBuildMarkup>(), val2);
			NavMeshBuildSettings val3 = default(NavMeshBuildSettings);
			((NavMeshBuildSettings)(ref val3)).agentHeight = 4f;
			((NavMeshBuildSettings)(ref val3)).agentRadius = 4f;
			((NavMeshBuildSettings)(ref val3)).agentSlope = 0f;
			((NavMeshBuildSettings)(ref val3)).agentClimb = 0f;
			val3.m_LedgeDropHeight = 50f;
			val3.m_MaxJumpAcrossDistance = 8f;
			_navMeshData = NavMeshBuilder.BuildNavMeshData(val3, val2, val, center, Quaternion.identity);
			_validSpawnPoints.Clear();
		}

		private static Vector3 GetReachablePoint(Vector3 origin, Vector3 direction, float distance)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0019: Unknown result type (might be due to invalid IL or missing references)
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(origin, direction);
			RaycastHit val2 = default(RaycastHit);
			if (!Physics.Raycast(val, ref val2, distance, 13))
			{
				return ((Ray)(ref val)).GetPoint(distance);
			}
			return ((RaycastHit)(ref val2)).point + direction * (0f - Math.Min(1f, ((RaycastHit)(ref val2)).distance));
		}

		private static bool CanReachAny(Vector3 source, params Vector3[] targets)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return targets.Any(delegate(Vector3 t)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: 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)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				if (Vector3.Distance(source, t) < 1f)
				{
					return true;
				}
				Vector3 val = t - source;
				return (!Physics.Raycast(new Ray(source, ((Vector3)(ref val)).normalized), ((Vector3)(ref val)).magnitude, 13)) ? true : false;
			});
		}

		private static bool CanWalkPath(IReadOnlyList<Vector3> nodes)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.up * 1f;
			for (int i = 0; i < nodes.Count - 1; i++)
			{
				int index = i + 1;
				Vector3 val2 = nodes[i] + val;
				Vector3 val3 = nodes[index] + val - val2;
				if (Physics.Raycast(new Ray(val2, ((Vector3)(ref val3)).normalized), ((Vector3)(ref val3)).magnitude, 13))
				{
					return false;
				}
			}
			return true;
		}

		public static Vector3? GetRandomPoint(int tries, Vector3 canReach, params AvoidSpawningNear[] avoid)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Invalid comparison between Unknown and I4
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_navMeshData == (Object)null)
			{
				return null;
			}
			Vector3[] targets = (Vector3[])(object)new Vector3[3]
			{
				canReach,
				GetReachablePoint(canReach, Vector3.up, 10f),
				GetReachablePoint(canReach, Vector3.down, 10f)
			};
			float num = _radius / 2f;
			SortedList<int, Vector3> sortedList = new SortedList<int, Vector3>();
			NavMeshHit val = default(NavMeshHit);
			for (int i = 0; i < tries; i++)
			{
				if (!NavMesh.SamplePosition(canReach + Random.insideUnitSphere * num, ref val, _radius, -1))
				{
					continue;
				}
				Vector3 target = ((NavMeshHit)(ref val)).position;
				NavMeshPath val2 = new NavMeshPath();
				NavMesh.CalculatePath(target, canReach, -1, val2);
				foreach (Vector3 item in (Il2CppArrayBase<Vector3>)(object)val2.corners)
				{
					_ = item;
				}
				if ((int)val2.status == 1)
				{
					target = ((IEnumerable<Vector3>)val2.corners).Last();
				}
				if (CanReachAny(((IEnumerable<Vector3>)val2.corners).LastOrDefault(target), targets) && CanWalkPath((IReadOnlyList<Vector3>)val2.corners))
				{
					int num2 = avoid.Count(delegate(AvoidSpawningNear a)
					{
						//IL_0001: Unknown result type (might be due to invalid IL or missing references)
						//IL_0007: Unknown result type (might be due to invalid IL or missing references)
						//IL_000c: 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)
						Vector3 val5 = a.Position - target;
						return ((Vector3)(ref val5)).sqrMagnitude < a.RadiusSquare;
					});
					if (num2 <= 0)
					{
						_validSpawnPoints.Add(target);
						return target;
					}
					sortedList.Add(avoid.Length - num2, target);
				}
			}
			foreach (KeyValuePair<int, Vector3> item2 in sortedList)
			{
				item2.Deconstruct(out var _, out var value);
				Vector3 val3 = value;
				NavMeshPath val4 = new NavMeshPath();
				NavMesh.CalculatePath(val3, canReach, -1, val4);
				if (CanReachAny(((IEnumerable<Vector3>)val4.corners).LastOrDefault(val3), targets) && CanWalkPath((IReadOnlyList<Vector3>)val4.corners))
				{
					return val3;
				}
			}
			if (_validSpawnPoints.Count <= 0)
			{
				return null;
			}
			return IEnumerableExtensions.GetRandom<Vector3>((IEnumerable<Vector3>)_validSpawnPoints);
		}

		public static void SetRandomSpawn(int tries, Vector3 fallback, Vector3 canReach, params AvoidSpawningNear[] avoid)
		{
			//IL_0001: 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)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			Vector3? randomPoint = GetRandomPoint(tries, canReach, avoid);
			if (!randomPoint.HasValue)
			{
				MelonLogger.Error("Failed to find any spawnpoint! this is a bug.");
				SetSpawn(fallback);
			}
			else
			{
				SetSpawn(randomPoint.Value);
			}
		}
	}
}
namespace MashGamemodeLibrary.Player.Loadout
{
	public class Loadout
	{
		private static readonly List<SlotType> AllSlotTypes = Enum.GetValues(typeof(SlotType)).Cast<SlotType>().ToList();

		private static readonly SlotData DefaultSlotData = new SlotData(null);

		private readonly Dictionary<SlotType, SlotData> _slotAssigners = new Dictionary<SlotType, SlotData>();

		public Loadout()
		{
			foreach (SlotType value in Enum.GetValues(typeof(SlotType)))
			{
				_slotAssigners[value] = new SlotData();
			}
		}

		public Loadout SetSlotBarcode(SlotType slotType, Barcode? barcode)
		{
			_slotAssigners[slotType] = new SlotData(barcode);
			return this;
		}

		public void Assign()
		{
			RigManager rigManager = Player.RigManager;
			foreach (SlotType allSlotType in AllSlotTypes)
			{
				_slotAssigners.GetValueOrDefault(allSlotType, DefaultSlotData).AssignSlot(rigManager, allSlotType);
			}
		}

		public static void ClearPlayerLoadout(RigManager rig)
		{
			foreach (SlotType value in Enum.GetValues(typeof(SlotType)))
			{
				DefaultSlotData.AssignSlot(rig, value);
			}
			ClearHeadSlot(rig);
		}

		public static void ClearHeadSlot(RigManager rig)
		{
			Transform obj = ((Rig)rig.physicsRig).m_head.FindChild("HeadSlotContainer");
			InventorySlotReceiver val = ((obj != null) ? ((Component)obj).GetComponentInChildren<InventorySlotReceiver>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				val.DespawnContents();
			}
		}
	}
}
namespace MashGamemodeLibrary.Player.Helpers
{
	public static class CrippleHelper
	{
		public static bool IsCrippled
		{
			get
			{
				PlayerData localPlayerData = PlayerDataManager.GetLocalPlayerData();
				if (localPlayerData == null)
				{
					return false;
				}
				if (!localPlayerData.CheckRule((PlayerCrippledRule p) => p.IsEnabled))
				{
					return localPlayerData.CheckRule((PlayerSpectatingRule p) => p.IsSpectating);
				}
				return true;
			}
		}
	}
	public static class InteractionExtender
	{
		public static bool HasInteractions(this NetworkPlayer player)
		{
			if (!NetworkSceneManager.IsLevelNetworked)
			{
				return true;
			}
			return PlayerDataManager.GetPlayerData(player)?.CheckRule((PlayerSpectatingRule r) => r.IsSpectating) ?? true;
		}

		public static bool HasLocalInteractions()
		{
			if (!NetworkSceneManager.IsLevelNetworked)
			{
				return true;
			}
			return PlayerDataManager.GetLocalPlayerData()?.CheckRule((PlayerSpectatingRule r) => r.IsSpectating) ?? true;
		}
	}
	internal struct NightVisionObject
	{
		public GameObject GameObject;

		public ColorAdjustments ColorAdjustments;

		public readonly void SetActive(bool state)
		{
			if (Object.op_Implicit((Object)(object)GameObject))
			{
				GameObject.SetActive(state);
			}
		}

		public readonly void SetColor(Color color)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			((VolumeParameter<Color>)(object)ColorAdjustments.colorFilter).value = color;
		}

		public readonly void SetBrightness(float value)
		{
			((VolumeParameter<float>)(object)ColorAdjustments.postExposure).value = value;
		}
	}
	public static class NightVisionHelper
	{
		private static bool _nightVisionEnabled;

		private static float _nightVisionBrightness = 1f;

		private static NightVisionObject? _instance;

		public static bool Enabled
		{
			get
			{
				return _nightVisionEnabled;
			}
			set
			{
				ToggleNightVision(value);
			}
		}

		public static float Brightness
		{
			get
			{
				return _nightVisionBrightness;
			}
			set
			{
				_nightVisionBrightness = value;
				_instance?.SetBrightness(value);
			}
		}

		private static void ToggleNightVision(bool isEnabled)
		{
			_nightVisionEnabled = isEnabled;
			GetOrCreate().SetActive(isEnabled);
		}

		private static NightVisionObject GetOrCreate()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (_instance.HasValue && Object.op_Implicit((Object)(object)_instance.Value.GameObject))
			{
				return _instance.Value;
			}
			GameObject val = new GameObject("VisionManager");
			val.transform.rotation = Quaternion.LookRotation(Vector3.down);
			GameObject val2 = val;
			Volume obj = val2.AddComponent<Volume>();
			obj.isGlobal = true;
			obj.priority = 10f;
			obj.weight = 1f;
			VolumeProfile val4 = (obj.sharedProfile = ScriptableObject.CreateInstance<VolumeProfile>());
			ColorAdjustments val5 = val4.Add<ColorAdjustments>(true);
			((VolumeParameter<float>)(object)val5.contrast).value = 20f;
			((VolumeParameter<float>)(object)val5.postExposure).value = _nightVisionBrightness;
			((VolumeParameter<Color>)(object)val5.colorFilter).value = Color.white;
			Light obj2 = val2.AddComponent<Light>();
			obj2.color = Color.white;
			obj2.range = 120f;
			obj2.intensity = 1f;
			obj2.type = (LightType)1;
			obj2.shadows = (LightShadows)0;
			NightVisionObject value = default(NightVisionObject);
			value.GameObject = val2;
			value.ColorAdjustments = val5;
			_instance = value;
			return _instance.Value;
		}
	}
	public static class PlayerComponentExtender
	{
		public static void ClearPlayerComponents()
		{
			Executor.RunIfHost(delegate
			{
				foreach (NetworkPlayer player in NetworkPlayer.Players)
				{
					player.NetworkEntity.ClearComponents();
				}
			});
		}

		public static bool TryGetComponent<T>(this NetworkPlayer player, [MaybeNullWhen(false)] out T component) where T : class, IComponent
		{
			if (player.NetworkEntity == null)
			{
				component = null;
				return false;
			}
			component = player.NetworkEntity.GetComponent<T>();
			return component != null;
		}

		public static bool HasComponent<T>(this NetworkPlayer player) where T : class, IComponent
		{
			NetworkEntity networkEntity = player.NetworkEntity;
			return ((networkEntity != null) ? networkEntity.GetComponent<T>() : null) != null;
		}

		public static bool HasComponent<T>(this NetworkPlayer player, Func<T, bool> predicate) where T : class, IComponent
		{
			if (player.NetworkEntity == null)
			{
				return false;
			}
			T component = player.NetworkEntity.GetComponent<T>();
			if (component != null)
			{
				return predicate(component);
			}
			return false;
		}

		public static void AddComponent(this NetworkPlayer player, IComponent component)
		{
			player.NetworkEntity?.AddComponent(component);
		}

		public static void AddComponents(this NetworkPlayer player, params IComponent[] components)
		{
			if (player.NetworkEntity != null)
			{
				foreach (IComponent component in components)
				{
					player.NetworkEntity.AddComponent(component);
				}
			}
		}

		public static bool TryAddComponent<T>(this NetworkPlayer player, Func<T> factory) where T : class, IComponent
		{
			if (player.NetworkEntity.GetComponent<T>() != null)
			{
				return false;
			}
			player.NetworkEntity.AddComponent(factory());
			return true;
		}

		public static void RemoveComponent<T>(this NetworkPlayer player) where T : class, IComponent
		{
			player.NetworkEntity?.RemoveComponent<T>();
		}

		public static void ToggleComponent<T>(this NetworkPlayer player, bool state, Func<T> factory) where T : class, IComponent
		{
			if (player.NetworkEntity != null)
			{
				if (state)
				{
					player.TryAddComponent(factory);
				}
				else
				{
					player.RemoveComponent<T>();
				}
			}
		}
	}
	public static class SpawnPointHelper
	{
		private static GameObject? _spawnPoint;

		private static GameObject GetSpawnPoint()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			if ((Object)(object)_spawnPoint == (Object)null)
			{
				_spawnPoint = new GameObject();
			}
			return _spawnPoint;
		}

		public static void SetSpawnPoint(Vector3 position)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			GameObject spawnPoint = GetSpawnPoint();
			spawnPoint.transform.SetPositionAndRotation(position, Quaternion.identity);
			FusionPlayer.SetSpawnPoints((Transform[])(object)new Transform[1] { spawnPoint.transform });
		}
	}
	public static class SpectatorExtender
	{
		private static PlayerRuleInstance<PlayerSpectatingRule> GetOrCreateSpectatingModifier(PlayerID playerId)
		{
			return (PlayerDataManager.GetPlayerData(PlayerID.op_Implicit(playerId)) ?? throw new Exception($"Player data not found for player ID: {playerId}")).GetRuleInstance<PlayerSpectatingRule>();
		}

		public static bool IsSpectating(this NetworkPlayer player)
		{
			return PlayerDataManager.GetPlayerData(player)?.CheckRule((PlayerSpectatingRule r) => r.IsSpectating) ?? false;
		}

		public static bool IsSpectating(this PlayerID playerId)
		{
			return PlayerDataManager.GetPlayerData(PlayerID.op_Implicit(playerId))?.CheckRule((PlayerSpectatingRule r) => r.IsSpectating) ?? false;
		}

		public static bool IsLocalPlayerSpectating()
		{
			return PlayerDataManager.GetLocalPlayerData()?.CheckRule((PlayerSpectatingRule r) => r.IsSpectating) ?? false;
		}

		public static void SetSpectating(this NetworkPlayer player, bool isSpectating)
		{
			player.PlayerID.SetSpectating(isSpectating);
		}

		public static void SetSpectating(this PlayerID playerID, bool isSpectating)
		{
			GetOrCreateSpectatingModifier(playerID).Modify(delegate(PlayerSpectatingRule rule)
			{
				rule.IsSpectating = isSpectating;
			});
		}

		public static void StopSpectatingAll()
		{
			PlayerDataManager.ForEachPlayerData(delegate(PlayerData data)
			{
				data.GetRuleInstance<PlayerSpectatingRule>().Modify(delegate(PlayerSpectatingRule rule)
				{
					rule.IsSpectating = false;
				});
			});
		}
	}
}
namespace MashGamemodeLibrary.Player.Data
{
	internal record NetworkRulePacket(PlayerID PlayerID, ulong RuleHash);
	[RequireStaticConstructor]
	public class PlayerData : IEventReceiver
	{
		private static readonly IBehaviourCache<IPlayerRuleChangedCallback> PlayerRuleChangedCache = BehaviourManager.CreateCache<IPlayerRuleChangedCallback>();

		private static readonly FactoryTypedRegistry<IPlayerExtender> ExtenderRegistry = new FactoryTypedRegistry<IPlayerExtender>();

		private static readonly FactoryTypedRegistry<IPlayerRule> RuleRegistry = new FactoryTypedRegistry<IPlayerRule>();

		private static readonly FactoryTypedRegistry<IEventCaller> EventCallerRegistry = new FactoryTypedRegistry<IEventCaller>();

		private readonly Dictionary<Type, IPlayerExtender> _extenderCache = new Dictionary<Type, IPlayerExtender>();

		private readonly Dictionary<Type, IPlayerRuleInstance> _ruleInstanceCache = new Dictionary<Type, IPlayerRuleInstance>();

		private readonly Dictionary<ulong, IPlayerRuleInstance> _ruleHashCache = new Dictionary<ulong, IPlayerRuleInstance>();

		private readonly Dictionary<Type, IEventCaller> _eventCallerCache = new Dictionary<Type, IEventCaller>();

		private readonly Dictionary<Type, List<IPlayerExtender>> _ruleChangeCallbacks = new Dictionary<Type, List<IPlayerExtender>>();

		private readonly Dictionary<Type, List<IPlayerExtender>> _eventCallbacks = new Dictionary<Type, List<IPlayerExtender>>();

		private static readonly NetworkRuleChangeEvent NetworkRuleChangeEvent = new NetworkRuleChangeEvent("PlayerData.RuleChange");

		private static readonly NetworkRuleBulkChangeEvent NetworkRuleBulkChangeEvent = new NetworkRuleBulkChangeEvent("PlayerData.RuleBulkChange");

		public PlayerID PlayerID { get; init; }

		public NetworkPlayer? NetworkPlayer { get; private set; }

		public IEnumerable<IPlayerExtender> Extenders => _extenderCache.Values;

		public IEnumerable<IPlayerRuleInstance> RuleInstances => _ruleInstanceCache.Values;

		public IEnumerable<IEventCaller> EventCallers => _eventCallerCache.Values;

		public static void Register<TMod>()
		{
			ExtenderRegistry.RegisterAll<TMod>();
			RuleRegistry.RegisterAll<TMod>();
			EventCallerRegistry.RegisterAll<TMod>();
		}

		public PlayerData(PlayerID playerID)
		{
			PlayerID = playerID;
			IEnumerableExtensions.ForEach<IPlayerExtender>(ExtenderRegistry.GetAll(), (Action<IPlayerExtender>)AddExtender);
			IEnumerableExtensions.ForEach<Type>(RuleRegistry.GetAllTypes(), (Action<Type>)AddRule);
			IEnumerableExtensions.ForEach<IEventCaller>(EventCallerRegistry.GetAll(), (Action<IEventCaller>)AddEventCaller);
		}

		private void AddExtender(IPlayerExtender playerExtender)
		{
			_extenderCache.Add(playerExtender.GetType(), playerExtender);
			foreach (Type ruleType in playerExtender.RuleTypes)
			{
				_ruleChangeCallbacks.GetValueOrCreate(ruleType).Add(playerExtender);
			}
			foreach (Type eventType in playerExtender.EventTypes)
			{
				_eventCallbacks.GetValueOrCreate(eventType).Add(playerExtender);
			}
		}

		private void AddRule<TRule>() where TRule : class, IPlayerRule, new()
		{
			PlayerRuleInstance<TRule> playerRuleInstance = new PlayerRuleInstance<TRule>(this);
			_ruleInstanceCache.Add(typeof(TRule), playerRuleInstance);
			_ruleHashCache.Add(playerRuleInstance.Hash, playerRuleInstance);
		}

		private void AddRule(Type ruleType)
		{
			IPlayerRuleInstance playerRuleInstance = (IPlayerRuleInstance)Activator.CreateInstance(typeof(PlayerRuleInstance<>).MakeGenericType(ruleType), this);
			_ruleInstanceCache.Add(ruleType, playerRuleInstance);
			_ruleHashCache.Add(playerRuleInstance.Hash, playerRuleInstance);
		}

		private void AddEventCaller(IEventCaller eventCaller)
		{
			_eventCallerCache.Add(eventCaller.GetType(), eventCaller);
		}

		internal void NotifyRuleChanged(IPlayerRuleInstance ruleInstance)
		{
			IPlayerRuleInstance ruleInstance2 = ruleInstance;
			IPlayerRule rule = ruleInstance2.GetBaseRule();
			_ruleChangeCallbacks.GetValueOrDefault(rule.GetType())?.ForEach(delegate(IPlayerExtender e)
			{
				e.OnRuleChanged(this);
			});
			PlayerDataManager.CallEventOnAll(new PlayerRuleChangedEvent(PlayerID, rule));
			if (NetworkPlayer != null)
			{
				PlayerRuleChangedCache.ForEach(delegate(IPlayerRuleChangedCallback e)
				{
					e.OnPlayerRuleChanged(NetworkPlayer, rule);
				});
			}
			Executor.RunIfHost(delegate
			{
				NetworkRuleChangeEvent.Send(PlayerID, ruleInstance2);
			});
		}

		internal void NotifyAllRules()
		{
			foreach (IPlayerExtender value in _extenderCache.Values)
			{
				value.OnRuleChanged(this);
			}
			foreach (IPlayerRuleInstance ruleInstance in RuleInstances)
			{
				IPlayerRule rule = ruleInstance.GetBaseRule();
				PlayerDataManager.CallEventOnAll(new PlayerRuleChangedEvent(PlayerID, rule));
				if (NetworkPlayer != null)
				{
					PlayerRuleChangedCache.ForEach(delegate(IPlayerRuleChangedCallback e)
					{
						e.OnPlayerRuleChanged(NetworkPlayer, rule);
					});
				}
			}
			Executor.RunIfHost(delegate
			{
				NetworkRuleBulkChangeEvent.Send(this);
			});
		}

		public void OnRigCreated(NetworkPlayer player, RigManager rigManager)
		{
			NetworkPlayer player2 = player;
			RigManager rigManager2 = rigManager;
			NetworkPlayer = player2;
			IEnumerableExtensions.ForEach<IPlayerExtender>(Extenders, (Action<IPlayerExtender>)delegate(IPlayerExtender e)
			{
				e.OnPlayerChanged(player2, rigManager2);
			});
			IEnumerableExtensions.ForEach<IEventCaller>(EventCallers, (Action<IEventCaller>)delegate(IEventCaller e)
			{
				e.OnEnable(this, player2);
			});
		}

		public bool CheckRule<TRule>(Func<TRule, bool> predicate) where TRule : class, IPlayerRule, new()
		{
			if (!_ruleInstanceCache.TryGetValue(typeof(TRule), out IPlayerRuleInstance value))
			{
				return false;
			}
			if (!(value is PlayerRuleInstance<TRule> playerRuleInstance))
			{
				return false;
			}
			return predicate(playerRuleInstance.GetRule());
		}

		public TRule GetRule<TRule>() where TRule : class, IPlayerRule, new()
		{
			if (!_ruleInstanceCache.TryGetValue(typeof(TRule), out IPlayerRuleInstance value))
			{
				throw new KeyNotFoundException($"Rule of type {typeof(TRule)} not found for player {PlayerID}");
			}
			return ((value as PlayerRuleInstance<TRule>) ?? throw new InvalidCastException($"Rule instance of type {value.GetType()} cannot be cast to PlayerRuleInstance<{typeof(TRule)}> for player {PlayerID}")).GetRule();
		}

		public void ModifyRule<TRule>(PlayerRuleInstance<TRule>.ModifyRuleDelegate modifier) where TRule : class, IPlayerRule, new()
		{
			if (!_ruleInstanceCache.TryGetValue(typeof(TRule), out IPlayerRuleInstance value))
			{
				throw new KeyNotFoundException($"Rule of type {typeof(TRule)} not found for player {PlayerID}");
			}
			((value as PlayerRuleInstance<TRule>) ?? throw new InvalidCastException($"Rule instance of type {value.GetType()} cannot be cast to PlayerRuleInstance<{typeof(TRule)}> for player {PlayerID}")).Modify(modifier);
		}

		public IPlayerRuleInstance? GetRuleByHash(ulong hash)
		{
			return _ruleHashCache.GetValueOrDefault(hash);
		}

		public PlayerRuleInstance<TRule> GetRuleInstance<TRule>() where TRule : class, IPlayerRule, new()
		{
			if (!_ruleInstanceCache.TryGetValue(typeof(TRule), out IPlayerRuleInstance value))
			{
				throw new KeyNotFoundException($"Rule of type {typeof(TRule)} not found for player {PlayerID}");
			}
			return value as PlayerRuleInstance<TRule>;
		}

		public T GetExtender<T>() where T : class, IPlayerExtender
		{
			if (!_extenderCache.TryGetValue(typeof(T), out IPlayerExtender value))
			{
				throw new KeyNotFoundException($"Extender of type {typeof(T)} not found for player {PlayerID}");
			}
			return value as T;
		}

		public void ResetRules()
		{
			foreach (IPlayerRuleInstance ruleInstance in RuleInstances)
			{
				ruleInstance.Reset(notify: false);
			}
			NotifyAllRules();
		}

		public void SendCatchup(PlayerID playerID)
		{
			NetworkRuleBulkChangeEvent.SendTo(playerID, this);
		}

		public void ReceiveEvent(IPlayerEvent playerEvent)
		{
			IPlayerEvent playerEvent2 = playerEvent;
			IEnumerableExtensions.ForEach<IPlayerExtender>(Extenders, (Action<IPlayerExtender>)delegate(IPlayerExtender e)
			{
				e.OnEvent(playerEvent2);
			});
		}
	}
	public static class PlayerDataManager
	{
		private static readonly Dictionary<byte, PlayerData> PlayerData;

		static PlayerDataManager()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			PlayerData = new Dictionary<byte, PlayerData>();
			MultiplayerHooking.OnPlayerJoined += new PlayerUpdate(OnPlayerJoined);
			MultiplayerHooking.OnPlayerLeft += new PlayerUpdate(OnPlayerLeft);
			NetworkPlayer.OnNetworkRigCreated += OnNetworkRigCreated;
		}

		private static void OnPlayerJoined(PlayerID playerID)
		{
			PlayerID playerID2 = playerID;
			PlayerData.GetValueOrCreate(PlayerID.op_Implicit(playerID2), () => new PlayerData(playerID2));
		}

		private static void OnNetworkRigCreated(NetworkPlayer networkPlayer, RigManager rigManager)
		{
			PlayerID playerID = networkPlayer.PlayerID;
			PlayerData.GetValueOrCreate(PlayerID.op_Implicit(playerID), () => new PlayerData(playerID)).OnRigCreated(networkPlayer, rigManager);
		}

		private static void OnPlayerLeft(PlayerID playerId)
		{
			PlayerData.Remove(PlayerID.op_Implicit(playerId));
		}

		public static PlayerData? GetPlayerData(NetworkPlayer networkPlayer)
		{
			if (!networkPlayer.HasRig)
			{
				return null;
			}
			return PlayerData.GetValueOrDefault(PlayerID.op_Implicit(networkPlayer.PlayerID));
		}

		public static PlayerData? GetOrCreatePlayerData(byte playerID)
		{
			if (PlayerData.TryGetValue(playerID, out PlayerData value))
			{
				return value;
			}
			NetworkPlayer val = default(NetworkPlayer);
			if (!NetworkPlayerManager.TryGetPlayer(playerID, ref val))
			{
				return null;
			}
			PlayerData playerData = new PlayerData(val.PlayerID);
			PlayerData[playerID] = playerData;
			if (val.HasRig)
			{
				playerData.OnRigCreated(val, val.RigRefs.RigManager);
			}
			return playerData;
		}

		public static PlayerData? GetPlayerData(byte playerID)
		{
			return GetOrCreatePlayerData(playerID);
		}

		public static bool TryGetPlayerData(PlayerID playerId, [MaybeNullWhen(false)] out PlayerData playerData)
		{
			playerData = GetOrCreatePlayerData(PlayerID.op_Implicit(playerId));
			return playerData != null;
		}

		public static PlayerData? GetLocalPlayerData()
		{
			if (PlayerIDManager.LocalID == null)
			{
				return null;
			}
			return GetOrCreatePlayerData(PlayerIDManager.LocalSmallID);
		}

		public static void ForEachPlayerData(Action<PlayerData> action)
		{
			foreach (PlayerData value in PlayerData.Values)
			{
				action(value);
			}
		}

		public static void ModifyAll<TRule>(PlayerRuleInstance<TRule>.ModifyRuleDelegate modifier) where TRule : class, IPlayerRule, new()
		{
			PlayerRuleInstance<TRule>.ModifyRuleDelegate modifier2 = modifier;
			ForEachPlayerData(delegate(PlayerData playerData)
			{
				playerData.ModifyRule(modifier2);
			});
		}

		public static void ResetRules()
		{
			foreach (PlayerData value in PlayerData.Values)
			{
				value.ResetRules();
			}
		}

		public static void Clear()
		{
			PlayerData.Clear();
		}

		internal static void SendCatchup(PlayerID playerID)
		{
			PlayerID playerID2 = playerID;
			ForEachPlayerData(delegate(PlayerData playerData)
			{
				playerData.SendCatchup(playerID2);
			});
		}

		internal static void CallEventOnAll(IPlayerEvent playerEvent)
		{
			IPlayerEvent playerEvent2 = playerEvent;
			ForEachPlayerData(delegate(PlayerData playerData)
			{
				playerData.ReceiveEvent(playerEvent2);
			});
		}
	}
}
namespace MashGamemodeLibrary.Player.Data.Rules
{
	public interface IPlayerRule : INetSerializable
	{
		bool IsEnabled { get; }

		int GetHash();
	}
	public interface IPlayerRuleInstance
	{
		ulong Hash { get; }

		void Deserialize(NetReader reader, bool notify = true);

		IPlayerRule GetBaseRule();

		void Reset(bool notify = true);
	}
	public class PlayerRuleInstance<TRule> : IPlayerRuleInstance where TRule : class, IPlayerRule, new()
	{
		public delegate void ModifyRuleDelegate(TRule rule);

		private readonly PlayerData _playerData;

		private TRule _localRule = new TRule();

		private readonly TRule _networkedRule = new TRule();

		public ulong Hash { get; }

		public PlayerRuleInstance(PlayerData playerData)
		{
			_playerData = playerData;
			Hash = typeof(TRule).GetStableHash();
		}

		public void Modify(ModifyRuleDelegate modifier)
		{
			if (!NetworkInfo.IsHost)
			{
				InternalLogger.Error("Player Rules can't be edited on the client");
				return;
			}
			int hash = _localRule.GetHash();
			modifier.Try(delegate(ModifyRuleDelegate m)
			{
				m(_localRule);
			});
			if (hash != _localRule.GetHash())
			{
				NotifyChange();
			}
		}

		public void NotifyChange()
		{
			_playerData.NotifyRuleChanged(this);
		}

		public TRule GetRule()
		{
			if (NetworkInfo.IsClient)
			{
				return _networkedRule;
			}
			return _localRule;
		}

		public IPlayerRule GetBaseRule()
		{
			return GetRule();
		}

		public void Reset(bool notifyChange = true)
		{
			_localRule = new TRule();
			if (notifyChange)
			{
				NotifyChange(