Decompiled source of Possessed Masks v2.1.1

PossessedMasks.dll

Decompiled 7 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using PossessedMasks.NetcodePatcher;
using PossessedMasks.mono;
using PossessedMasks.networking;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("PossessedMasks")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+879fe035f095123ebe4ec9395f13aa2e5db21493")]
[assembly: AssemblyProduct("PossessedMasks")]
[assembly: AssemblyTitle("PossessedMasks")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PossessedMasks
{
	public static class ModConfig
	{
		internal static ConfigEntry<bool> EnableMaskPossessionMechanic;

		internal static ConfigEntry<bool> EnableMaskSwitchSlotMechanic;

		internal static ConfigEntry<int> EnableChangeMaskSpawnChance;

		internal static ConfigEntry<int> NumberOfSlotsFilledToEnableDroppingMask;

		internal static ConfigEntry<float> TimeToStartSwitchingSlots;

		internal static ConfigEntry<float> TimeToStartPossession;

		internal static ConfigEntry<bool> TwoHandedItemBehaviour;

		internal static ConfigEntry<int> MaskRarity;

		internal static ConfigEntry<bool> MaskRarityScaling;

		internal static ConfigEntry<float> MaskRarityScalingMultiplier;

		internal static ConfigEntry<int> MinMaskItemBaseValue;

		internal static ConfigEntry<int> MaxMaskItemBaseValue;

		internal static ConfigEntry<float> MinTimeToSwitchSlots;

		internal static ConfigEntry<float> MaxTimeToSwitchSlots;

		internal static ConfigEntry<float> DeltaTimeToSwitchSlots;

		internal static ConfigEntry<float> MinSwitchingSlotTime;

		internal static ConfigEntry<float> MinTimeToPossess;

		internal static ConfigEntry<float> MaxTimeToPossess;

		internal static ConfigEntry<float> DeltaTimeToPossess;

		internal static ConfigEntry<float> MinPossessingTime;

		internal static ConfigEntry<float> MinTimeToPossessPlayer;

		internal static ConfigEntry<float> MaxTimeToPossessPlayer;

		internal static ConfigEntry<float> DeltaTimeToPossessPlayer;

		internal static ConfigEntry<float> MaxPossessingPlayerTime;

		internal static bool Loaded { get; private set; }

		internal static void Init(ConfigFile config)
		{
			EnableMaskPossessionMechanic = config.Bind<bool>("Mechanics", "EnableMaskPossessionMechanic", true, "If true, mask possession mechanic will be enabled");
			EnableMaskSwitchSlotMechanic = config.Bind<bool>("Mechanics", "EnableMaskSwitchSlotMechanic", true, "If true, mask switching to your active slot mechanic will be enabled");
			EnableChangeMaskSpawnChance = config.Bind<int>("Mechanics", "EnableChangeMaskSpawnChance", 2, "If 0, will not override mask spawn chance, scrap value and available levels.\nIf 1, will override spawn chance, scrap value but not available levels.\nif 2 will override all of them.\nif 3 will override value but non of the other stuff");
			NumberOfSlotsFilledToEnableDroppingMask = config.Bind<int>("General", "NumberOfSlotsFilledToEnableDroppingMask", 3, "Number of inventory slots that need to be filled to enable dropping a mask");
			TimeToStartSwitchingSlots = config.Bind<float>("General", "TimeToStartSwitchingSlots", 5f, "After this much time with mask in inventory start switching slots");
			TimeToStartPossession = config.Bind<float>("General", "TimeToStartPossession", 10f, "After this much time with mask in inventory start possessions");
			TwoHandedItemBehaviour = config.Bind<bool>("General", "TwoHandedItemBehaviour", true, "If true, 2 handed items will be dropped when switching slots");
			MaskRarity = config.Bind<int>("Mask Rarity", "MaskRarity", 35, "Rarity of mask item 0 - 100 (0 - doesn't spawn, 100 - spawns a lot)");
			MaskRarityScaling = config.Bind<bool>("Mask Rarity", "MaskRarityScaling", true, "If true, mask rarity will be scaled up by moon rank");
			MaskRarityScalingMultiplier = config.Bind<float>("Mask Rarity", "MaskRarityScalingMultiplier", 0.5f, "Multiplier for mask rarity scaling");
			MinMaskItemBaseValue = config.Bind<int>("Mask Item Base Value", "MinMaskItemBaseValue", 100, "Minimum base value of mask item (affected by multipliers >1)");
			MaxMaskItemBaseValue = config.Bind<int>("Mask Item Base Value", "MaxMaskItemBaseValue", 150, "Maximum base value of mask item (affected by multipliers >1)");
			MinTimeToSwitchSlots = config.Bind<float>("Time To Switch Slots", "MinTimeToSwitchSlots", 12f, "Minimum time between switching slots");
			MaxTimeToSwitchSlots = config.Bind<float>("Time To Switch Slots", "MaxTimeToSwitchSlots", 20f, "Maximum time between switching slots");
			DeltaTimeToSwitchSlots = config.Bind<float>("Time To Switch Slots", "DeltaTimeToSwitchSlots", 0.5f, "Time to subtract from min and max each time a switch happens");
			MinSwitchingSlotTime = config.Bind<float>("Time To Switch Slots", "MinSwitchingSlotTime", 3f, "The number at which subtracting from min and max stops");
			MinTimeToPossess = config.Bind<float>("Time To Possess", "MinTimeToPossess", 20f, "Minimum time between possessions");
			MaxTimeToPossess = config.Bind<float>("Time To Possess", "MaxTimeToPossess", 30f, "Maximum time between possessions");
			DeltaTimeToPossess = config.Bind<float>("Time To Possess", "DeltaTimeToPossess", 1f, "Time to subtract from min and max each time a possession happens");
			MinPossessingTime = config.Bind<float>("Time To Possess", "MinPossessingTime", 10f, "The number at which subtracting from min and max stops");
			MinTimeToPossessPlayer = config.Bind<float>("Item Activation Time", "MinTimeToPossessPlayer", 2f, "Minimum time of actual possession");
			MaxTimeToPossessPlayer = config.Bind<float>("Item Activation Time", "MaxTimeToPossessPlayer", 4f, "Maximum time of actual possession");
			DeltaTimeToPossessPlayer = config.Bind<float>("Item Activation Time", "DeltaTimeToPossessPlayer", 1f, "Time to add to min and max each time a possession happens");
			MaxPossessingPlayerTime = config.Bind<float>("Item Activation Time", "MaxPossessingPlayerTime", 9f, "The number at which adding to min and max stops");
			Loaded = true;
		}
	}
	[BepInDependency("evaisa.lethallib", "0.14.1")]
	[BepInPlugin("oe.tweaks.qol.possessedmasks", "Possessed Masks", "2.0.4")]
	public class Plugin : BaseUnityPlugin
	{
		private readonly Harmony harmony = new Harmony("oe.tweaks.qol.possessedmasks");

		public const string Guid = "oe.tweaks.qol.possessedmasks";

		internal const string Name = "Possessed Masks";

		public const string Version = "2.0.4";

		internal static Plugin Instance;

		internal static List<GameObject> NetworkPrefabs = new List<GameObject>();

		internal static ManualLogSource Log;

		private AssetBundle _ab;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"'Possessed Masks' is loading...");
			if (!Object.op_Implicit((Object)(object)Instance))
			{
				Instance = this;
			}
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			_ab = AssetBundle.LoadFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetManifestResourceNames()[0]));
			if (!Object.op_Implicit((Object)(object)_ab))
			{
				Log.LogError((object)"Failed to load asset bundle");
				return;
			}
			Log.LogInfo((object)"Asset bundle loaded");
			Utils.PossessionSounds.Add(_ab.LoadAsset<AudioClip>("possession1"));
			Utils.PossessionSounds.Add(_ab.LoadAsset<AudioClip>("possession2"));
			Utils.PossessionSounds.Add(_ab.LoadAsset<AudioClip>("possession3"));
			Utils.SlotSwitchSounds.Add(_ab.LoadAsset<AudioClip>("slot1"));
			Utils.SlotSwitchSounds.Add(_ab.LoadAsset<AudioClip>("slot2"));
			GameObject val = NetworkPrefabs.CreateNetworkPrefab("PossessedBehaviour");
			val.AddComponent<PossessedBehaviour>();
			NetworkPrefabs.Add(val);
			InitializeNetworkRoutine();
			harmony.PatchAll();
			Log.LogInfo((object)"'Possessed Masks' loaded!");
		}

		private void OnDestroy()
		{
			Instance = null;
		}

		private void InitializeNetworkRoutine()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			Type[] array = types;
			foreach (Type type in array)
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo[] array2 = methods;
				foreach (MethodInfo methodInfo in array2)
				{
					object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
					if (customAttributes.Length != 0)
					{
						try
						{
							methodInfo.Invoke(null, null);
						}
						catch (Exception arg)
						{
							Log.LogError((object)$"Failed to invoke method {methodInfo.Name}: {arg}");
						}
					}
				}
			}
		}
	}
	public static class SharedConfig
	{
		public static int ItemCount { get; set; }

		public static bool TwoHandedBehaviour { get; set; }

		internal static IEnumerator DelayedRequestConfig()
		{
			if (Utils.HostCheck)
			{
				yield return (object)new WaitUntil((Func<bool>)(() => ModConfig.Loaded));
				ItemCount = ModConfig.NumberOfSlotsFilledToEnableDroppingMask.Value;
				TwoHandedBehaviour = ModConfig.TwoHandedItemBehaviour.Value;
			}
			else
			{
				yield return (object)new WaitUntil((Func<bool>)(() => Object.op_Implicit((Object)(object)PossessedBehaviour.Instance)));
				PossessedBehaviour.Instance.RequestConfigServerRpc();
			}
		}
	}
	public static class Utils
	{
		public static Item TragedyItem;

		public static Item ComedyItem;

		public static Dictionary<Type, GameObject> EnemyPrefabRegistry = new Dictionary<Type, GameObject>();

		public static List<AudioClip> PossessionSounds = new List<AudioClip>();

		public static List<AudioClip> SlotSwitchSounds = new List<AudioClip>();

		public static Terminal Terminal;

		private static bool _registered;

		public static List<GameObject> InsideAINodes;

		public static List<GameObject> OutsideAINodes;

		public static bool HostCheck => NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer;

		public static bool InLevel => Object.op_Implicit((Object)(object)StartOfRound.Instance) && !StartOfRound.Instance.inShipPhase && StartOfRound.Instance.currentLevelID != 3;

		private static void RegisterEnemyPrefab(Type enemyAI, GameObject prefab)
		{
			if (typeof(EnemyAI).IsAssignableFrom(enemyAI))
			{
				EnemyPrefabRegistry.TryAdd(enemyAI, prefab);
			}
		}

		private static void SetComedyAndTragedy()
		{
			ComedyItem = ((IEnumerable<Item>)StartOfRound.Instance.allItemsList.itemsList).FirstOrDefault((Func<Item, bool>)((Item item) => item.itemName == "Comedy"));
			TragedyItem = ((IEnumerable<Item>)StartOfRound.Instance.allItemsList.itemsList).FirstOrDefault((Func<Item, bool>)((Item item) => item.itemName == "Tragedy"));
			if (!Object.op_Implicit((Object)(object)ComedyItem))
			{
				Plugin.Log.LogMessage((object)"Comedy item not found!");
			}
			else
			{
				Plugin.Log.LogMessage((object)"Comedy item found!");
				ComedyItem.minValue = ModConfig.MinMaskItemBaseValue.Value;
				ComedyItem.maxValue = ModConfig.MaxMaskItemBaseValue.Value;
			}
			if (!Object.op_Implicit((Object)(object)TragedyItem))
			{
				Plugin.Log.LogMessage((object)"Tragedy item not found!");
				return;
			}
			Plugin.Log.LogMessage((object)"Tragedy item found!");
			TragedyItem.minValue = ModConfig.MinMaskItemBaseValue.Value;
			TragedyItem.maxValue = ModConfig.MaxMaskItemBaseValue.Value;
		}

		private static void TweakSpawnChanceAndMoons()
		{
			SelectableLevel[] moonsCatalogueList = Terminal.moonsCatalogueList;
			float value = ModConfig.MaskRarityScalingMultiplier.Value;
			SelectableLevel[] array = moonsCatalogueList;
			foreach (SelectableLevel val in array)
			{
				int rarity2 = Mathf.Clamp(Mathf.RoundToInt((float)ModConfig.MaskRarity.Value + (ModConfig.MaskRarityScaling.Value ? (value * (float)val.maxTotalScrapValue / 100f) : 0f)), 0, 100);
				val.Enemies.ForEach(delegate(SpawnableEnemyWithRarity spawnable)
				{
					GameObject enemyPrefab = spawnable.enemyType.enemyPrefab;
					RegisterEnemyPrefab(((object)enemyPrefab.GetComponent<EnemyAI>()).GetType(), enemyPrefab);
				});
				if (ModConfig.EnableChangeMaskSpawnChance.Value != 0)
				{
					SetMoonSpawn(ComedyItem, rarity2, val);
					SetMoonSpawn(TragedyItem, rarity2, val);
				}
			}
			static void SetMoonSpawn(Item item, int rarity, SelectableLevel level)
			{
				//IL_0025: 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: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Expected O, but got Unknown
				if (Object.op_Implicit((Object)(object)item))
				{
					SpawnableItemWithRarity val2 = new SpawnableItemWithRarity
					{
						spawnableItem = item,
						rarity = rarity
					};
					int num = level.spawnableScrap.FindIndex((SpawnableItemWithRarity lvlItem) => lvlItem.spawnableItem.itemName == item.itemName);
					if (num != -1)
					{
						if (ModConfig.EnableChangeMaskSpawnChance.Value == 3)
						{
							level.spawnableScrap[num].spawnableItem = val2.spawnableItem;
						}
						else
						{
							level.spawnableScrap[num] = val2;
						}
					}
					else if (ModConfig.EnableChangeMaskSpawnChance.Value == 2)
					{
						level.spawnableScrap.Add(val2);
					}
				}
			}
		}

		public static void RegisterAll()
		{
			if (!_registered && Object.op_Implicit((Object)(object)Terminal) && Object.op_Implicit((Object)(object)StartOfRound.Instance))
			{
				_registered = true;
				Plugin.Log.LogMessage((object)"Registering all!");
				SetComedyAndTragedy();
				TweakSpawnChanceAndMoons();
			}
		}

		public static void PlayRandomAudioClipFromList(AudioSource source, List<AudioClip> clips, float volumeScale = 1f)
		{
			source.PlayOneShot(clips[Random.Range(0, clips.Count)], volumeScale);
		}

		public static int MathMod(int muduli, int modulus)
		{
			return (muduli % modulus + modulus) % modulus;
		}

		public static bool IsActivePlayer(PlayerControllerB player)
		{
			return Object.op_Implicit((Object)(object)player) && player.isPlayerControlled && !player.isPlayerDead;
		}

		public static int ItemCount(PlayerControllerB player)
		{
			return player.ItemSlots.Count((GrabbableObject item) => Object.op_Implicit((Object)(object)item));
		}

		public static List<PlayerControllerB> GetActivePlayers(bool inside)
		{
			return Object.op_Implicit((Object)(object)ServerManager.Instance) ? ServerManager.Instance.ActivePlayers.FindAll((PlayerControllerB player) => player.isInsideFactory == inside) : new List<PlayerControllerB>();
		}

		public static (bool, T) FindFarthestAwayThingFromPosition<T>(Vector3 position, List<T> things, Func<T, Vector3> getThingPosition)
		{
			//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)
			if (!things.Any())
			{
				return (false, default(T));
			}
			T farthestAwayThing = default(T);
			float farthestAwayThingDistance = float.NegativeInfinity;
			bool found = false;
			things.ForEach(delegate(T thing)
			{
				//IL_0002: 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)
				float num = Vector3.Distance(position, getThingPosition(thing));
				if (num > farthestAwayThingDistance)
				{
					farthestAwayThingDistance = num;
					farthestAwayThing = thing;
					found = true;
				}
			});
			return (found, farthestAwayThing);
		}

		public static (bool, T) FindClosestThingToPosition<T>(Vector3 position, List<T> things, Func<T, Vector3> getThingPosition)
		{
			//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)
			if (!things.Any())
			{
				return (false, default(T));
			}
			T closestThing = default(T);
			float closestThingDistance = float.PositiveInfinity;
			bool found = false;
			things.ForEach(delegate(T thing)
			{
				//IL_0002: 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)
				float num = Vector3.Distance(position, getThingPosition(thing));
				if (num < closestThingDistance)
				{
					closestThingDistance = num;
					closestThing = thing;
					found = true;
				}
			});
			return (found, closestThing);
		}

		public static bool PathNotVisibleByPlayer(NavMeshPath path)
		{
			//IL_0010: 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)
			Vector3[] corners = path.corners;
			for (int i = 1; i < corners.Length; i++)
			{
				if (Physics.Linecast(corners[i - 1], corners[i], 262144))
				{
					return false;
				}
			}
			return true;
		}
	}
}
namespace PossessedMasks.patches
{
	[HarmonyPatch(typeof(GameNetworkManager))]
	public class GameNetworkManagerPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void StartPostfix(GameNetworkManager __instance)
		{
			Plugin.NetworkPrefabs.ForEach(delegate(GameObject prefab)
			{
				NetworkManager.Singleton.AddNetworkPrefab(prefab);
			});
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	public class PlayerControllerBPatch
	{
		[HarmonyPatch("Discard_performed")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Discard_performedPrefix(PlayerControllerB __instance)
		{
			PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController;
			GrabbableObject currentlyHeldObjectServer = localPlayerController.currentlyHeldObjectServer;
			if (Utils.InLevel)
			{
				HauntedMaskItem val = (HauntedMaskItem)(object)((currentlyHeldObjectServer is HauntedMaskItem) ? currentlyHeldObjectServer : null);
				if (val != null && val.maskIsHaunted && Utils.ItemCount(localPlayerController) < SharedConfig.ItemCount)
				{
					return false;
				}
			}
			return true;
		}

		[HarmonyPatch("Interact_performed")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Interact_performedPrefix(PlayerControllerB __instance)
		{
			PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController;
			GrabbableObject currentlyHeldObjectServer = localPlayerController.currentlyHeldObjectServer;
			if (Utils.InLevel)
			{
				HauntedMaskItem val = (HauntedMaskItem)(object)((currentlyHeldObjectServer is HauntedMaskItem) ? currentlyHeldObjectServer : null);
				if (val != null && val.maskIsHaunted && (localPlayerController.activatingItem || Utils.ItemCount(localPlayerController) < SharedConfig.ItemCount))
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	public class RoundManagerPatch
	{
		[HarmonyPatch("FinishGeneratingLevel")]
		[HarmonyPostfix]
		private static void FinishGeneratingLevelPostfix(RoundManager __instance)
		{
			Utils.InsideAINodes = __instance.insideAINodes.ToList();
			Utils.OutsideAINodes = __instance.outsideAINodes.ToList();
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	public class StartOfRoundPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void AwakePostfix()
		{
			if (Utils.HostCheck)
			{
				Plugin.Log.LogMessage((object)"Spawning network prefabs (host only)");
				Plugin.NetworkPrefabs.ForEach(delegate(GameObject prefab)
				{
					//IL_0002: Unknown result type (might be due to invalid IL or missing references)
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					Object.Instantiate<GameObject>(prefab, Vector3.zero, Quaternion.identity).GetComponent<NetworkObject>().Spawn(false);
				});
			}
		}

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPostfix(StartOfRound __instance)
		{
			if (Utils.HostCheck)
			{
				Plugin.Log.LogMessage((object)"Starting manager (host only)");
				((Component)__instance).gameObject.AddComponent<ServerManager>();
				Utils.RegisterAll();
			}
		}
	}
	[HarmonyPatch(typeof(Terminal))]
	public class TerminalPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPostfix(Terminal __instance)
		{
			Utils.Terminal = __instance;
			if (Utils.HostCheck)
			{
				Utils.RegisterAll();
			}
		}
	}
}
namespace PossessedMasks.networking
{
	public class PossessedBehaviour : NetworkBehaviour
	{
		public static PossessedBehaviour Instance { get; private set; }

		private static bool IsMyPlayer(ulong ownerId)
		{
			Plugin.Log.LogDebug((object)$"Local Owner ID: {((NetworkBehaviour)StartOfRound.Instance.localPlayerController).OwnerClientId}, Owner ID: {ownerId}");
			return Object.op_Implicit((Object)(object)StartOfRound.Instance.localPlayerController) && ((NetworkBehaviour)StartOfRound.Instance.localPlayerController).OwnerClientId == ownerId;
		}

		public override void OnNetworkSpawn()
		{
			((NetworkBehaviour)this).OnNetworkSpawn();
			Instance = this;
			((MonoBehaviour)this).StartCoroutine(SharedConfig.DelayedRequestConfig());
		}

		public override void OnNetworkDespawn()
		{
			((NetworkBehaviour)this).OnNetworkDespawn();
			Instance = null;
		}

		[ServerRpc(RequireOwnership = false)]
		public void RequestConfigServerRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(1017191677u, val, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 1017191677u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && Utils.HostCheck)
				{
					((MonoBehaviour)this).StartCoroutine(DelayedSendConfig());
				}
			}
		}

		private IEnumerator DelayedSendConfig()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => ModConfig.Loaded));
			SendConfigClientRpc(ModConfig.NumberOfSlotsFilledToEnableDroppingMask.Value, ModConfig.TwoHandedItemBehaviour.Value);
		}

		[ClientRpc]
		private void SendConfigClientRpc(int itemCount, bool twoHandedBehaviour)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val = default(ClientRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(3950309743u, val, (RpcDelivery)0);
					BytePacker.WriteValueBitPacked(val2, itemCount);
					((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref twoHandedBehaviour, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendClientRpc(ref val2, 3950309743u, val, (RpcDelivery)0);
				}
				if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && !Utils.HostCheck)
				{
					SharedConfig.ItemCount = itemCount;
					SharedConfig.TwoHandedBehaviour = twoHandedBehaviour;
				}
			}
		}

		[ServerRpc]
		public void StartPossessionServerRpc(ulong ownerId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Invalid comparison between Unknown and I4
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId)
				{
					if ((int)networkManager.LogLevel <= 1)
					{
						Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!");
					}
					return;
				}
				ServerRpcParams val = default(ServerRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(1097494237u, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, ownerId);
				((NetworkBehaviour)this).__endSendServerRpc(ref val2, 1097494237u, val, (RpcDelivery)0);
			}
			if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				StartPossessionClientRpc(ownerId);
			}
		}

		[ClientRpc]
		private void StartPossessionClientRpc(ulong ownerId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val = default(ClientRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(3265900518u, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, ownerId);
				((NetworkBehaviour)this).__endSendClientRpc(ref val2, 3265900518u, val, (RpcDelivery)0);
			}
			if ((int)base.__rpc_exec_stage != 2 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			if (IsMyPlayer(ownerId))
			{
				if (!Object.op_Implicit((Object)(object)StartOfRound.Instance.localPlayerController.currentlyHeldObjectServer))
				{
					return;
				}
				GrabbableObject currentlyHeldObjectServer = StartOfRound.Instance.localPlayerController.currentlyHeldObjectServer;
				HauntedMaskItem val3 = (HauntedMaskItem)(object)((currentlyHeldObjectServer is HauntedMaskItem) ? currentlyHeldObjectServer : null);
				if (val3 != null)
				{
					if ((double)Random.Range(0f, 1f) >= 0.33)
					{
						Utils.PlayRandomAudioClipFromList(val3.maskAudio, Utils.PossessionSounds);
					}
					((GrabbableObject)val3).ActivateItemServerRpc(true, true);
					((GrabbableObject)val3).ItemActivate(true, true);
				}
			}
			else
			{
				Plugin.Log.LogDebug((object)"StartPossessionClientRPC: not owner");
			}
		}

		[ServerRpc]
		public void StopPossessionServerRpc(ulong ownerId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Invalid comparison between Unknown and I4
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId)
				{
					if ((int)networkManager.LogLevel <= 1)
					{
						Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!");
					}
					return;
				}
				ServerRpcParams val = default(ServerRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(3653823995u, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, ownerId);
				((NetworkBehaviour)this).__endSendServerRpc(ref val2, 3653823995u, val, (RpcDelivery)0);
			}
			if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				StopPossessionClientRpc(ownerId);
			}
		}

		[ClientRpc]
		private void StopPossessionClientRpc(ulong ownerId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val = default(ClientRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(2606043065u, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, ownerId);
				((NetworkBehaviour)this).__endSendClientRpc(ref val2, 2606043065u, val, (RpcDelivery)0);
			}
			if ((int)base.__rpc_exec_stage != 2 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			if (IsMyPlayer(ownerId))
			{
				if (Object.op_Implicit((Object)(object)StartOfRound.Instance.localPlayerController.currentlyHeldObjectServer))
				{
					GrabbableObject currentlyHeldObjectServer = StartOfRound.Instance.localPlayerController.currentlyHeldObjectServer;
					HauntedMaskItem val3 = (HauntedMaskItem)(object)((currentlyHeldObjectServer is HauntedMaskItem) ? currentlyHeldObjectServer : null);
					if (val3 != null)
					{
						((GrabbableObject)val3).ActivateItemServerRpc(false, false);
						((GrabbableObject)val3).ItemActivate(false, false);
					}
				}
			}
			else
			{
				Plugin.Log.LogDebug((object)"DeactivateMaskClientRPC: not owner");
			}
		}

		[ServerRpc]
		public void SwitchSlotServerRpc(ulong ownerId, bool forward, int maskSlot)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Invalid comparison between Unknown and I4
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId)
				{
					if ((int)networkManager.LogLevel <= 1)
					{
						Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!");
					}
					return;
				}
				ServerRpcParams val = default(ServerRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(3141266536u, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, ownerId);
				((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref forward, default(ForPrimitives));
				BytePacker.WriteValueBitPacked(val2, maskSlot);
				((NetworkBehaviour)this).__endSendServerRpc(ref val2, 3141266536u, val, (RpcDelivery)0);
			}
			if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				SwitchSlotClientRpc(ownerId, forward, maskSlot);
			}
		}

		[ClientRpc]
		private void SwitchSlotClientRpc(ulong ownerId, bool forward, int maskSlot)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val = default(ClientRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(1217869235u, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, ownerId);
				((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref forward, default(ForPrimitives));
				BytePacker.WriteValueBitPacked(val2, maskSlot);
				((NetworkBehaviour)this).__endSendClientRpc(ref val2, 1217869235u, val, (RpcDelivery)0);
			}
			if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost))
			{
				if (IsMyPlayer(ownerId))
				{
					((MonoBehaviour)this).StartCoroutine(DelayedSlotSwitch(forward, maskSlot));
				}
				else
				{
					Plugin.Log.LogDebug((object)"SwitchSlotClientRPC: not owner");
				}
			}
		}

		private IEnumerator DelayedSlotSwitch(bool forward, int maskSlot)
		{
			PlayerControllerB localPlayer = StartOfRound.Instance.localPlayerController;
			GrabbableObject potentialMask = localPlayer.ItemSlots[maskSlot];
			if ((double)Random.Range(0f, 1f) >= 0.33)
			{
				HauntedMaskItem mask = default(HauntedMaskItem);
				int num;
				if (Object.op_Implicit((Object)(object)potentialMask))
				{
					mask = (HauntedMaskItem)(object)((potentialMask is HauntedMaskItem) ? potentialMask : null);
					num = ((mask != null) ? 1 : 0);
				}
				else
				{
					num = 0;
				}
				if (num != 0)
				{
					Utils.PlayRandomAudioClipFromList(mask.maskAudio, Utils.SlotSwitchSounds);
				}
			}
			localPlayer.playerActions.FindAction("ActivateItem", false).Disable();
			localPlayer.playerActions.FindAction("SwitchItem", false).Disable();
			GrabbableObject currentHeld = localPlayer.ItemSlots[localPlayer.currentItemSlot];
			if (Object.op_Implicit((Object)(object)currentHeld) && (currentHeld.isBeingUsed || localPlayer.activatingItem))
			{
				currentHeld.UseItemOnClient(false);
				yield return (object)new WaitForEndOfFrame();
			}
			if (SharedConfig.TwoHandedBehaviour && localPlayer.twoHanded)
			{
				GrabbableObject heldObject = localPlayer.currentlyHeldObject;
				yield return ((MonoBehaviour)this).StartCoroutine(localPlayer.waitToEndOfFrameToDiscard());
				yield return (object)new WaitForEndOfFrame();
				heldObject.EnableItemMeshes(true);
			}
			localPlayer.SwitchToItemSlot(localPlayer.NextItemSlot(forward), (GrabbableObject)null);
			localPlayer.SwitchItemSlotsServerRpc(forward);
			localPlayer.playerActions.FindAction("ActivateItem", false).Enable();
			localPlayer.playerActions.FindAction("SwitchItem", false).Enable();
		}

		protected override void __initializeVariables()
		{
			((NetworkBehaviour)this).__initializeVariables();
		}

		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeRPCS_PossessedBehaviour()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			NetworkManager.__rpc_func_table.Add(1017191677u, new RpcReceiveHandler(__rpc_handler_1017191677));
			NetworkManager.__rpc_func_table.Add(3950309743u, new RpcReceiveHandler(__rpc_handler_3950309743));
			NetworkManager.__rpc_func_table.Add(1097494237u, new RpcReceiveHandler(__rpc_handler_1097494237));
			NetworkManager.__rpc_func_table.Add(3265900518u, new RpcReceiveHandler(__rpc_handler_3265900518));
			NetworkManager.__rpc_func_table.Add(3653823995u, new RpcReceiveHandler(__rpc_handler_3653823995));
			NetworkManager.__rpc_func_table.Add(2606043065u, new RpcReceiveHandler(__rpc_handler_2606043065));
			NetworkManager.__rpc_func_table.Add(3141266536u, new RpcReceiveHandler(__rpc_handler_3141266536));
			NetworkManager.__rpc_func_table.Add(1217869235u, new RpcReceiveHandler(__rpc_handler_1217869235));
		}

		private static void __rpc_handler_1017191677(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0029: 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)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((PossessedBehaviour)(object)target).RequestConfigServerRpc();
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_3950309743(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				int itemCount = default(int);
				ByteUnpacker.ReadValueBitPacked(reader, ref itemCount);
				bool twoHandedBehaviour = default(bool);
				((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref twoHandedBehaviour, default(ForPrimitives));
				target.__rpc_exec_stage = (__RpcExecStage)2;
				((PossessedBehaviour)(object)target).SendConfigClientRpc(itemCount, twoHandedBehaviour);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_1097494237(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId)
			{
				if ((int)networkManager.LogLevel <= 1)
				{
					Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!");
				}
			}
			else
			{
				ulong ownerId = default(ulong);
				ByteUnpacker.ReadValueBitPacked(reader, ref ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((PossessedBehaviour)(object)target).StartPossessionServerRpc(ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_3265900518(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				ulong ownerId = default(ulong);
				ByteUnpacker.ReadValueBitPacked(reader, ref ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)2;
				((PossessedBehaviour)(object)target).StartPossessionClientRpc(ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_3653823995(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId)
			{
				if ((int)networkManager.LogLevel <= 1)
				{
					Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!");
				}
			}
			else
			{
				ulong ownerId = default(ulong);
				ByteUnpacker.ReadValueBitPacked(reader, ref ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((PossessedBehaviour)(object)target).StopPossessionServerRpc(ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_2606043065(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				ulong ownerId = default(ulong);
				ByteUnpacker.ReadValueBitPacked(reader, ref ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)2;
				((PossessedBehaviour)(object)target).StopPossessionClientRpc(ownerId);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_3141266536(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId)
			{
				if ((int)networkManager.LogLevel <= 1)
				{
					Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!");
				}
				return;
			}
			ulong ownerId = default(ulong);
			ByteUnpacker.ReadValueBitPacked(reader, ref ownerId);
			bool forward = default(bool);
			((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref forward, default(ForPrimitives));
			int maskSlot = default(int);
			ByteUnpacker.ReadValueBitPacked(reader, ref maskSlot);
			target.__rpc_exec_stage = (__RpcExecStage)1;
			((PossessedBehaviour)(object)target).SwitchSlotServerRpc(ownerId, forward, maskSlot);
			target.__rpc_exec_stage = (__RpcExecStage)0;
		}

		private static void __rpc_handler_1217869235(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				ulong ownerId = default(ulong);
				ByteUnpacker.ReadValueBitPacked(reader, ref ownerId);
				bool forward = default(bool);
				((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref forward, default(ForPrimitives));
				int maskSlot = default(int);
				ByteUnpacker.ReadValueBitPacked(reader, ref maskSlot);
				target.__rpc_exec_stage = (__RpcExecStage)2;
				((PossessedBehaviour)(object)target).SwitchSlotClientRpc(ownerId, forward, maskSlot);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		protected internal override string __getTypeName()
		{
			return "PossessedBehaviour";
		}
	}
}
namespace PossessedMasks.mono
{
	public class ServerManager : MonoBehaviour
	{
		private class PlayerProps
		{
			public float TimeUntilSlotSwitch = Random.Range(ModConfig.MinTimeToSwitchSlots.Value, ModConfig.MaxTimeToSwitchSlots.Value) + ModConfig.TimeToStartSwitchingSlots.Value;

			private float _timeUntilSlotSwitchDelta = 0f;

			public bool Possessing = false;

			public float TimeUntilPossession = Random.Range(ModConfig.MinTimeToPossess.Value, ModConfig.MaxTimeToPossess.Value) + ModConfig.TimeToStartPossession.Value;

			private float _timeUntilPossessionDelta = 0f;

			public float TimeUntilUnpossession = 0f;

			private float _timeUntilUnpossessionDelta = 0f;

			public void GenerateTimeUntilSlotSwitch()
			{
				_timeUntilSlotSwitchDelta += ModConfig.DeltaTimeToSwitchSlots.Value;
				TimeUntilSlotSwitch = Mathf.Clamp(Random.Range(ModConfig.MinTimeToSwitchSlots.Value - _timeUntilSlotSwitchDelta, ModConfig.MaxTimeToSwitchSlots.Value - _timeUntilSlotSwitchDelta), ModConfig.MinSwitchingSlotTime.Value, float.MaxValue);
			}

			public void GenerateTimeUntilPossession()
			{
				_timeUntilPossessionDelta += ModConfig.DeltaTimeToPossess.Value;
				TimeUntilPossession = Mathf.Clamp(Random.Range(ModConfig.MinTimeToPossess.Value - _timeUntilPossessionDelta, ModConfig.MaxTimeToPossess.Value - _timeUntilPossessionDelta), ModConfig.MinPossessingTime.Value, float.MaxValue);
			}

			public void GenerateTimeUntilUnpossession()
			{
				_timeUntilUnpossessionDelta += ModConfig.DeltaTimeToPossessPlayer.Value;
				TimeUntilUnpossession = Mathf.Clamp(Random.Range(ModConfig.MinTimeToPossessPlayer.Value + _timeUntilUnpossessionDelta, ModConfig.MaxTimeToPossessPlayer.Value + _timeUntilUnpossessionDelta), float.MinValue, ModConfig.MaxPossessingPlayerTime.Value);
			}
		}

		internal static ServerManager Instance;

		private int _currIndex;

		private bool _usingData = false;

		private readonly Dictionary<PlayerControllerB, PlayerProps> _playerProps = new Dictionary<PlayerControllerB, PlayerProps>();

		internal readonly List<PlayerControllerB> ActivePlayers = new List<PlayerControllerB>();

		private float _avgFrameTime;

		private bool ShouldUpdate => Utils.InLevel && ActivePlayers.Count > 0;

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(WaitUntilAllowed());
			Instance = this;
		}

		private void Update()
		{
			_avgFrameTime = (_avgFrameTime + Time.deltaTime) / 2f;
			if (!ShouldUpdate)
			{
				if (ActivePlayers.Count != 0 || _currIndex != 0)
				{
					ActivePlayers.Clear();
					_currIndex = 0;
				}
				return;
			}
			PlayerControllerB val = ActivePlayers[_currIndex];
			if (!_usingData && Utils.IsActivePlayer(val))
			{
				_usingData = true;
				DoInterval(val);
				_usingData = false;
				_currIndex = (_currIndex + 1) % ActivePlayers.Count;
			}
			else
			{
				ActivePlayers.Remove(val);
				_currIndex = 0;
			}
		}

		private void OnDestroy()
		{
			Instance = null;
		}

		private void DoInterval(PlayerControllerB player)
		{
			var (num, forward) = FindClosestMask(player);
			if (num != -1 && _playerProps.TryGetValue(player, out var value))
			{
				float num2 = _avgFrameTime * (float)ActivePlayers.Count;
				if (ModConfig.EnableMaskSwitchSlotMechanic.Value)
				{
					value.TimeUntilSlotSwitch -= num2;
				}
				if (ModConfig.EnableMaskPossessionMechanic.Value)
				{
					value.TimeUntilPossession -= num2;
					value.TimeUntilUnpossession -= num2;
				}
				if (value != null && value.Possessing && value.TimeUntilUnpossession <= 0f)
				{
					value.GenerateTimeUntilPossession();
					value.GenerateTimeUntilSlotSwitch();
					PossessedBehaviour.Instance.StopPossessionServerRpc(((NetworkBehaviour)player).OwnerClientId);
					value.Possessing = false;
				}
				else if (num == player.currentItemSlot && value != null && !value.Possessing && value.TimeUntilPossession <= 0f)
				{
					value.GenerateTimeUntilUnpossession();
					PossessedBehaviour.Instance.StartPossessionServerRpc(((NetworkBehaviour)player).OwnerClientId);
					value.Possessing = true;
				}
				else if (num != player.currentItemSlot && value != null && !value.Possessing && value.TimeUntilSlotSwitch <= 0f)
				{
					value.GenerateTimeUntilSlotSwitch();
					PossessedBehaviour.Instance.SwitchSlotServerRpc(((NetworkBehaviour)player).OwnerClientId, forward, num);
				}
			}
		}

		private IEnumerator NewLevel()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => !_usingData));
			_usingData = true;
			ActivePlayers.Clear();
			_playerProps.Clear();
			ActivePlayers.AddRange(StartOfRound.Instance.allPlayerScripts.Where(Utils.IsActivePlayer));
			ActivePlayers.ForEach(delegate(PlayerControllerB player)
			{
				_playerProps[player] = new PlayerProps();
			});
			_usingData = false;
		}

		private IEnumerator WaitUntilAllowed()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => Utils.InLevel));
			yield return (object)new WaitForEndOfFrame();
			((MonoBehaviour)this).StartCoroutine(NewLevel());
			yield return (object)new WaitUntil((Func<bool>)(() => !Utils.InLevel));
			yield return (object)new WaitForEndOfFrame();
			((MonoBehaviour)this).StartCoroutine(WaitUntilAllowed());
		}

		private static (int, bool) FindClosestMask(PlayerControllerB player)
		{
			int currentItemSlot = player.currentItemSlot;
			int num = player.ItemSlots.Length;
			for (int i = 0; i <= num / 2; i++)
			{
				int num2 = Utils.MathMod(currentItemSlot + i, num);
				if (Object.op_Implicit((Object)(object)player.ItemSlots[num2]))
				{
					GrabbableObject obj = player.ItemSlots[num2];
					HauntedMaskItem val = (HauntedMaskItem)(object)((obj is HauntedMaskItem) ? obj : null);
					if (val != null && val.maskIsHaunted)
					{
						return (num2, true);
					}
				}
				num2 = Utils.MathMod(currentItemSlot - i, num);
				if (Object.op_Implicit((Object)(object)player.ItemSlots[num2]))
				{
					GrabbableObject obj2 = player.ItemSlots[num2];
					HauntedMaskItem val = (HauntedMaskItem)(object)((obj2 is HauntedMaskItem) ? obj2 : null);
					if (val != null && val.maskIsHaunted)
					{
						return (num2, false);
					}
				}
			}
			return (-1, false);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace PossessedMasks.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}