Decompiled source of MonsterDisguise v0.2.0

MonsterDisguise.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MonsterDisguise")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+fae141119a7067697e9814571f6fa2d5faa1fa28")]
[assembly: AssemblyProduct("MonsterDisguise")]
[assembly: AssemblyTitle("MonsterDisguise")]
[assembly: AssemblyVersion("0.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MonsterDisguise
{
	public static class ConfigSettings
	{
		public static ConfigEntry<int> Price { get; private set; }

		public static ConfigEntry<float> DrainPerSecond { get; private set; }

		public static ConfigEntry<float> PuppetScale { get; private set; }

		public static ConfigEntry<string> ModelYawOverrides { get; private set; }

		public static void Bind(ConfigFile config)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			Price = config.Bind<int>("Shop", "Price", 8, new ConfigDescription("Shop price in money units (1 unit = $1k on screen).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			DrainPerSecond = config.Bind<float>("Disguise", "DrainPerSecond", 1.33f, new ConfigDescription("Battery drained per second while disguised (100 battery = ~75s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 50f), Array.Empty<object>()));
			PuppetScale = config.Bind<float>("Disguise", "PuppetScale", 1f, new ConfigDescription("Model scale of the monster puppet.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 3f), Array.Empty<object>()));
			ModelYawOverrides = config.Bind<string>("Disguise", "ModelYawOverrides", "", new ConfigDescription("Per-monster model yaw correction in degrees (\"ShortId=deg;...\"). Overrides the automatic facing detection.", (AcceptableValueBase)null, Array.Empty<object>()));
		}
	}
	[DefaultExecutionOrder(32766)]
	public class DisguiseBehavior : MonoBehaviour
	{
		private sealed class RemoteDisguise
		{
			public GameObject puppet;

			public GameObject visuals;

			public Transform root;

			public Dictionary<Transform, Vector3> snap;

			public string steamId;

			public float yawOffset;
		}

		private ItemAttributes activeItem;

		private string activeMonster;

		private GameObject puppet;

		private Transform hiddenRoot;

		private GameObject hiddenVisuals;

		private string noVisionId;

		private Dictionary<Transform, Vector3> snapshot;

		private Camera localCam;

		private List<Renderer> hiddenItemRenderers;

		private float puppetYawOffset;

		private static readonly string[] BeamObjects = new string[4] { "physGrabBeam", "physGrabPointVisual1", "physGrabPointVisual2", "physGrabPointVisualGridObject" };

		private readonly Dictionary<int, RemoteDisguise> remotes = new Dictionary<int, RemoteDisguise>();

		private readonly Dictionary<Transform, int> hideRefs = new Dictionary<Transform, int>();

		private const float DriftFreeze = 0.05f;

		private float chargeTick;

		private string lastFailKey;

		private readonly HashSet<Transform> spawnedRoots = new HashSet<Transform>();

		private static string lastYawSpec;

		private static Dictionary<string, float> yawOverrides;

		public static DisguiseBehavior Instance { get; private set; }

		public static PlayerAvatar LocalAvatar { get; private set; }

		public bool IsDisguised => (Object)(object)activeItem != (Object)null;

		public string ActiveMonster => activeMonster;

		private void Awake()
		{
			Instance = this;
		}

		private void TickFastCharge(float dt)
		{
			chargeTick += dt;
			if (chargeTick < 0.25f)
			{
				return;
			}
			float num = chargeTick;
			chargeTick = 0f;
			if ((Object)(object)RunManager.instance == (Object)null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			ItemBattery[] array = Object.FindObjectsOfType<ItemBattery>();
			foreach (ItemBattery val in array)
			{
				if ((Object)(object)val == (Object)null || val.batteryLife >= 100f)
				{
					continue;
				}
				IList list = GameAccess.Field<IList>(val, "chargerList");
				if (list != null && list.Count != 0)
				{
					ItemAttributes component = ((Component)val).GetComponent<ItemAttributes>();
					if (!((Object)(object)component == (Object)null) && DisguiseItems.IsOurs(((Object)((Component)component).gameObject).name))
					{
						val.batteryLife = Mathf.Min(100f, val.batteryLife + 20f * num);
					}
				}
			}
		}

		private static bool InLevel()
		{
			if ((Object)(object)LevelGenerator.Instance == (Object)null || (Object)(object)RunManager.instance == (Object)null || !(bool)AccessTools.Field(typeof(RunManager), "runStarted").GetValue(RunManager.instance))
			{
				return false;
			}
			Level levelCurrent = RunManager.instance.levelCurrent;
			if ((Object)(object)levelCurrent != (Object)null)
			{
				return levelCurrent.HasEnemies;
			}
			return false;
		}

		private void Update()
		{
			if ((Object)(object)LocalAvatar == (Object)null)
			{
				LocalAvatar = PlayerAvatar.instance;
			}
			TickFastCharge(Time.deltaTime);
			if (!InLevel())
			{
				if ((Object)(object)activeItem != (Object)null)
				{
					EndDisguise();
				}
				ClearRemotes();
			}
			else
			{
				if ((Object)(object)LocalAvatar == (Object)null)
				{
					return;
				}
				if ((Object)(object)activeItem == (Object)null)
				{
					ItemAttributes val = FindHeldActiveItem();
					if ((Object)(object)val != (Object)null)
					{
						TryStartDisguise(val);
					}
				}
				else
				{
					TickActive();
				}
			}
		}

		private void FixedUpdate()
		{
			if ((Object)(object)activeItem != (Object)null && (Object)(object)puppet != (Object)null)
			{
				PinPuppet(PlayerBodyRoot(), puppet, snapshot, isLocal: true, puppetYawOffset);
			}
			foreach (KeyValuePair<int, RemoteDisguise> remote in remotes)
			{
				PlayerAvatar val = FindAvatar(remote.Key);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)remote.Value.puppet == (Object)null))
				{
					PinPuppet(((Component)val).transform, remote.Value.puppet, remote.Value.snap, isLocal: false, remote.Value.yawOffset);
				}
			}
		}

		private static bool BodyGrounded()
		{
			try
			{
				object obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null);
				if (obj == null)
				{
					return true;
				}
				MemberInfo memberInfo = (MemberInfo)(((object)AccessTools.Property(obj.GetType(), "CollisionController")) ?? ((object)AccessTools.Field(obj.GetType(), "CollisionController")));
				object obj2 = null;
				if (memberInfo is PropertyInfo propertyInfo)
				{
					obj2 = propertyInfo.GetValue(obj);
				}
				else if (memberInfo is FieldInfo fieldInfo)
				{
					obj2 = fieldInfo.GetValue(obj);
				}
				if (obj2 == null)
				{
					return true;
				}
				MemberInfo memberInfo2 = (MemberInfo)(((object)AccessTools.Property(obj2.GetType(), "Grounded")) ?? ((object)AccessTools.Field(obj2.GetType(), "Grounded")));
				if (memberInfo2 is PropertyInfo propertyInfo2)
				{
					return (bool)propertyInfo2.GetValue(obj2);
				}
				if (memberInfo2 is FieldInfo fieldInfo2)
				{
					return (bool)fieldInfo2.GetValue(obj2);
				}
			}
			catch (Exception)
			{
			}
			return true;
		}

		private static PhysGrabber LocalGrabber()
		{
			try
			{
				if ((Object)(object)LocalAvatar == (Object)null)
				{
					return null;
				}
				object? obj = AccessTools.Field(typeof(PlayerAvatar), "physGrabber")?.GetValue(LocalAvatar);
				PhysGrabber val = (PhysGrabber)((obj is PhysGrabber) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				return ((Component)LocalAvatar).GetComponentInChildren<PhysGrabber>();
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static void HideBeam()
		{
			PhysGrabber val = LocalGrabber();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			string[] beamObjects = BeamObjects;
			foreach (string name in beamObjects)
			{
				GameObject val2 = GameAccess.Field<GameObject>(val, name);
				if ((Object)(object)val2 != (Object)null && val2.activeSelf)
				{
					val2.SetActive(false);
				}
			}
		}

		private static Transform PlayerBodyRoot()
		{
			object? obj = AccessTools.Field(typeof(PlayerController), "instance")?.GetValue(null);
			PlayerController val = (PlayerController)((obj is PlayerController) ? obj : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return ((Component)val).transform;
		}

		private static bool AvatarDead(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return true;
			}
			if (!(bool)AccessTools.Field(typeof(PlayerAvatar), "deadSet").GetValue(avatar))
			{
				return (bool)AccessTools.Field(typeof(PlayerAvatar), "isDisabled").GetValue(avatar);
			}
			return true;
		}

		private static ItemAttributes FindHeldActiveItem()
		{
			ItemAttributes[] array = Object.FindObjectsOfType<ItemAttributes>();
			foreach (ItemAttributes val in array)
			{
				if (!((Object)(object)val == (Object)null) && DisguiseItems.IsOurs(((Object)((Component)val).gameObject).name))
				{
					PhysGrabObject val2 = GameAccess.GrabObject(val);
					ItemToggle val3 = GameAccess.ToggleOf(val);
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null) && val3.toggleState && GameAccess.HeldByLocal(val2))
					{
						return val;
					}
				}
			}
			return null;
		}

		private static List<Renderer> HideItemRenderers(GameObject itemGo)
		{
			List<Renderer> list = new List<Renderer>();
			if ((Object)(object)itemGo == (Object)null)
			{
				return list;
			}
			Renderer[] componentsInChildren = itemGo.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && val.enabled)
				{
					val.enabled = false;
					list.Add(val);
				}
			}
			return list;
		}

		private void TickActive()
		{
			ItemToggle val = GameAccess.ToggleOf(activeItem);
			if ((Object)(object)activeItem == (Object)null || (Object)(object)val == (Object)null || !val.toggleState || AvatarDead(LocalAvatar))
			{
				EndDisguise();
				return;
			}
			HideBeam();
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			ItemBattery component = ((Component)activeItem).GetComponent<ItemBattery>();
			if (!((Object)(object)component == (Object)null))
			{
				component.Drain(ConfigSettings.DrainPerSecond.Value);
				if (component.batteryLife <= 0f)
				{
					val.ToggleItem(false, SemiFunc.PhotonViewIDPlayerAvatarLocal());
					EndDisguise();
				}
			}
		}

		private void FailOnce(string key, string message)
		{
			if (!(lastFailKey == key))
			{
				lastFailKey = key;
				Plugin.Log(message);
			}
		}

		private void TryStartDisguise(ItemAttributes item)
		{
			string setupName = DisguiseItems.SetupFor(((Object)((Component)item).gameObject).name);
			EnemySetup val = DisguiseItems.FindSetup(setupName);
			if ((Object)(object)val == (Object)null)
			{
				FailOnce(((Object)((Component)item).gameObject).name, "Disguise: no enemy setup for " + ((Object)((Component)item).gameObject).name);
				ForceToggleOff(item);
				return;
			}
			string text = DisguiseItems.ShortId(setupName);
			Transform val2 = AcquireSourceRoot(text, val);
			if ((Object)(object)val2 == (Object)null)
			{
				FailOnce(((Object)((Component)item).gameObject).name, "Disguise: no live " + text + " in level (host spawns one, clients need one around)");
				ForceToggleOff(item);
				return;
			}
			hiddenRoot = val2;
			((Component)val2).gameObject.SetActive(false);
			Transform val3 = PlayerBodyRoot();
			if ((Object)(object)val3 == (Object)null)
			{
				ReleaseSourceRoot(hiddenRoot);
				hiddenRoot = null;
				ForceToggleOff(item);
				return;
			}
			puppet = BuildPuppet(val2, val3);
			if ((Object)(object)puppet == (Object)null)
			{
				ReleaseSourceRoot(hiddenRoot);
				hiddenRoot = null;
				ForceToggleOff(item);
				return;
			}
			snapshot = CaptureSnapshot(puppet);
			puppetYawOffset = ResolveYawOffset(setupName, puppet);
			hiddenVisuals = HideVisuals(LocalAvatar);
			hiddenItemRenderers = HideItemRenderers(((Component)item).gameObject);
			HideBeam();
			noVisionId = AddNoVision(LocalAvatar);
			noVisionId = AddNoVision(LocalAvatar);
			activeItem = item;
			activeMonster = setupName;
			lastFailKey = null;
			DisguiseNetworking.Instance?.BroadcastState(DisguiseItems.IndexOfSetup(setupName), on: true);
			Plugin.Log("Disguise started: " + text);
		}

		private void EndDisguise()
		{
			if ((Object)(object)activeItem == (Object)null)
			{
				return;
			}
			string text = activeMonster;
			if ((Object)(object)puppet != (Object)null)
			{
				Object.Destroy((Object)(object)puppet);
				puppet = null;
			}
			snapshot = null;
			if ((Object)(object)hiddenRoot != (Object)null)
			{
				ReleaseSourceRoot(hiddenRoot);
				hiddenRoot = null;
			}
			if ((Object)(object)hiddenVisuals != (Object)null)
			{
				hiddenVisuals.SetActive(true);
				hiddenVisuals = null;
			}
			if (hiddenItemRenderers != null)
			{
				foreach (Renderer hiddenItemRenderer in hiddenItemRenderers)
				{
					if ((Object)(object)hiddenItemRenderer != (Object)null)
					{
						hiddenItemRenderer.enabled = true;
					}
				}
				hiddenItemRenderers = null;
			}
			if (noVisionId != null)
			{
				RemoveNoVision(noVisionId);
				noVisionId = null;
			}
			activeItem = null;
			activeMonster = null;
			int setupIdx = ((text != null) ? DisguiseItems.IndexOfSetup(text) : (-1));
			DisguiseNetworking.Instance?.BroadcastState(setupIdx, on: false);
			Plugin.Log("Disguise ended");
		}

		private static void ForceToggleOff(ItemAttributes item)
		{
			ItemToggle val = GameAccess.ToggleOf(item);
			if ((Object)(object)val != (Object)null && val.toggleState)
			{
				val.ToggleItem(false, SemiFunc.PhotonViewIDPlayerAvatarLocal());
			}
		}

		private Transform AcquireSourceRoot(string shortId, EnemySetup setup)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			string text = DisguiseItems.Norm(shortId);
			Enemy val = null;
			float num = float.MaxValue;
			Transform val2 = PlayerBodyRoot();
			Vector3 val3 = (((Object)(object)val2 != (Object)null) ? val2.position : Vector3.zero);
			Enemy[] array = Object.FindObjectsOfType<Enemy>();
			foreach (Enemy val4 in array)
			{
				if ((Object)(object)val4 == (Object)null)
				{
					continue;
				}
				string text2 = DisguiseItems.Norm(((object)val4).GetType().Name);
				if (!text2.Contains(text) && !text.Contains(text2))
				{
					continue;
				}
				Transform val5 = RootOf(val4);
				if (!((Object)(object)val5 == (Object)null))
				{
					float num2 = (((Object)(object)val2 != (Object)null) ? Vector3.Distance(val3, val5.position) : 0f);
					if (num2 < num)
					{
						num = num2;
						val = val4;
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				Transform val6 = RootOf(val);
				hideRefs[val6] = ((!hideRefs.TryGetValue(val6, out var value)) ? 1 : (value + 1));
				return val6;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)setup == (Object)null)
			{
				return null;
			}
			Vector3 val7 = val3 + Vector3.forward * 3f + Vector3.up * 1.5f;
			List<EnemyParent> list = null;
			try
			{
				list = Enemies.SpawnEnemy(setup, val7, Quaternion.identity, false);
			}
			catch (Exception ex)
			{
				Plugin.Log("Disguise spawn failed: " + ex.Message);
				return null;
			}
			Transform val8 = null;
			if (list != null)
			{
				foreach (EnemyParent item in list)
				{
					if (!((Object)(object)item == (Object)null))
					{
						if ((Object)(object)val8 == (Object)null)
						{
							val8 = ((Component)item).transform;
						}
						else
						{
							RemoveExtra(item);
						}
					}
				}
			}
			if ((Object)(object)val8 == (Object)null)
			{
				return null;
			}
			hideRefs[val8] = ((!hideRefs.TryGetValue(val8, out var value2)) ? 1 : (value2 + 1));
			spawnedRoots.Add(val8);
			Plugin.Log("Disguise: spawned " + shortId + " (host)");
			return val8;
		}

		private void ReleaseSourceRoot(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			if (hideRefs.TryGetValue(root, out var value))
			{
				value--;
				if (value <= 0)
				{
					hideRefs.Remove(root);
					if (spawnedRoots.Remove(root))
					{
						DespawnRoot(root);
					}
					else
					{
						((Component)root).gameObject.SetActive(true);
					}
				}
				else
				{
					hideRefs[root] = value;
				}
			}
			else if (spawnedRoots.Remove(root))
			{
				DespawnRoot(root);
			}
			else
			{
				((Component)root).gameObject.SetActive(true);
			}
		}

		private static void DespawnRoot(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			EnemyParent component = ((Component)root).GetComponent<EnemyParent>();
			if ((Object)(object)component == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)root).gameObject);
				return;
			}
			try
			{
				((Component)root).gameObject.SetActive(true);
				component.Despawn();
			}
			catch (Exception ex)
			{
				Plugin.Log("Disguise despawn failed: " + ex.Message);
				RemoveExtra(component);
			}
		}

		private static Transform RootOf(Enemy enemy)
		{
			if ((Object)(object)enemy == (Object)null)
			{
				return null;
			}
			EnemyParent value = Traverse.Create((object)enemy).Field("EnemyParent").GetValue<EnemyParent>();
			if (!((Object)(object)value != (Object)null))
			{
				return ((Component)enemy).transform.root;
			}
			return ((Component)value).transform;
		}

		private static void RemoveExtra(EnemyParent parent)
		{
			if (!((Object)(object)parent == (Object)null))
			{
				PhotonView val = ((Component)parent).GetComponent<PhotonView>() ?? ((Component)parent).GetComponentInChildren<PhotonView>();
				if ((Object)(object)val != (Object)null && PhotonNetwork.CurrentRoom != null && PhotonNetwork.IsMasterClient)
				{
					PhotonNetwork.Destroy(val);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)parent).gameObject);
				}
			}
		}

		private GameObject BuildPuppet(Transform source, Transform body)
		{
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			bool activeInHierarchy = ((Component)source).gameObject.activeInHierarchy;
			((Component)source).gameObject.SetActive(true);
			GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject);
			if (!activeInHierarchy)
			{
				((Component)source).gameObject.SetActive(false);
			}
			MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					((Behaviour)val2).enabled = false;
				}
			}
			NavMeshAgent[] componentsInChildren2 = val.GetComponentsInChildren<NavMeshAgent>(true);
			foreach (NavMeshAgent val3 in componentsInChildren2)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					((Behaviour)val3).enabled = false;
				}
			}
			EnemyRigidbody[] componentsInChildren3 = val.GetComponentsInChildren<EnemyRigidbody>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren3[i]);
			}
			EnemyParent[] componentsInChildren4 = val.GetComponentsInChildren<EnemyParent>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren4[i]);
			}
			PhotonView[] componentsInChildren5 = val.GetComponentsInChildren<PhotonView>(true);
			for (int i = 0; i < componentsInChildren5.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren5[i]);
			}
			Rigidbody[] componentsInChildren6 = val.GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren6.Length; i++)
			{
				componentsInChildren6[i].isKinematic = true;
			}
			Collider[] componentsInChildren7 = val.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren7.Length; i++)
			{
				componentsInChildren7[i].enabled = false;
			}
			((Object)val).name = "DisguisePuppet";
			val.transform.SetParent(body, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one * ConfigSettings.PuppetScale.Value;
			if (!val.activeSelf)
			{
				val.SetActive(true);
			}
			Plugin.Log("Puppet built under " + ((Object)body).name);
			return val;
		}

		private static float ResolveYawOffset(string setupName, GameObject puppetRoot)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			string value = ConfigSettings.ModelYawOverrides.Value;
			if (value != lastYawSpec)
			{
				lastYawSpec = value;
				yawOverrides = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
				string[] array = value.Split(';');
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split('=');
					if (array2.Length == 2 && float.TryParse(array2[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						yawOverrides[array2[0].Trim()] = result;
					}
				}
			}
			string text = DisguiseItems.ShortId(setupName);
			if (yawOverrides.TryGetValue(text, out var value2) || yawOverrides.TryGetValue(setupName ?? "", out value2))
			{
				Plugin.Log($"Disguise yaw for {text}: {value2} (config)");
				return value2;
			}
			float num = 0f;
			try
			{
				Bounds val = default(Bounds);
				((Bounds)(ref val))..ctor(puppetRoot.transform.position, Vector3.zero);
				bool flag = false;
				MeshRenderer[] componentsInChildren = puppetRoot.GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null && ((Renderer)val2).enabled)
					{
						((Bounds)(ref val)).Encapsulate(((Renderer)val2).bounds);
						flag = true;
					}
				}
				SkinnedMeshRenderer[] componentsInChildren2 = puppetRoot.GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val3 in componentsInChildren2)
				{
					if ((Object)(object)val3 != (Object)null && ((Renderer)val3).enabled)
					{
						((Bounds)(ref val)).Encapsulate(((Renderer)val3).bounds);
						flag = true;
					}
				}
				if (flag)
				{
					Vector3 val4 = puppetRoot.transform.InverseTransformPoint(((Bounds)(ref val)).center);
					val4.y = 0f;
					if (((Vector3)(ref val4)).magnitude >= 0.05f)
					{
						num = Mathf.Round(Vector3.SignedAngle(Vector3.forward, ((Vector3)(ref val4)).normalized, Vector3.up) / 90f) * 90f;
					}
				}
			}
			catch (Exception)
			{
			}
			Plugin.Log($"Disguise yaw for {text}: {num} (auto)");
			return num;
		}

		private static Dictionary<Transform, Vector3> CaptureSnapshot(GameObject root)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<Transform, Vector3> dictionary = new Dictionary<Transform, Vector3>();
			if ((Object)(object)root == (Object)null)
			{
				return dictionary;
			}
			Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)root.transform))
				{
					dictionary[val] = val.localPosition;
				}
			}
			return dictionary;
		}

		private void PinPuppet(Transform body, GameObject target, Dictionary<Transform, Vector3> snap, bool isLocal, float yawOffset)
		{
			//IL_0034: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)body == (Object)null || (Object)(object)target == (Object)null)
			{
				return;
			}
			if ((Object)(object)target.transform.parent != (Object)(object)body)
			{
				target.transform.SetParent(body, false);
			}
			float y = body.eulerAngles.y;
			if (isLocal)
			{
				if ((Object)(object)localCam == (Object)null)
				{
					localCam = Camera.main;
				}
				if ((Object)(object)localCam != (Object)null)
				{
					y = ((Component)localCam).transform.eulerAngles.y;
				}
			}
			Quaternion val = Quaternion.Euler(0f, y + yawOffset, 0f);
			if (Quaternion.Angle(target.transform.rotation, val) > 0.5f)
			{
				target.transform.rotation = val;
			}
			float num = GroundBelow(body.position, body, target.transform);
			Vector3 val2 = (Vector3)((isLocal && !BodyGrounded()) ? Vector3.zero : new Vector3(0f, num - body.position.y, 0f));
			Vector3 val3 = target.transform.localPosition - val2;
			if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f)
			{
				target.transform.localPosition = val2;
			}
			if (snap != null)
			{
				float num2 = 0.0025000002f;
				foreach (KeyValuePair<Transform, Vector3> item in snap)
				{
					if (!((Object)(object)item.Key == (Object)null))
					{
						val3 = item.Key.localPosition - item.Value;
						if (((Vector3)(ref val3)).sqrMagnitude > num2)
						{
							item.Key.localPosition = item.Value;
						}
					}
				}
			}
			DriveWalkAnim(target, body);
		}

		private static void DriveWalkAnim(GameObject target, Transform body)
		{
			//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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Animator componentInChildren = target.GetComponentInChildren<Animator>();
				if ((Object)(object)componentInChildren == (Object)null)
				{
					return;
				}
				bool flag = false;
				AnimatorControllerParameter[] parameters = componentInChildren.parameters;
				for (int i = 0; i < parameters.Length; i++)
				{
					if (parameters[i].name == "Moving")
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					Rigidbody componentInParent = ((Component)body).GetComponentInParent<Rigidbody>();
					float num = 0f;
					if ((Object)(object)componentInParent != (Object)null)
					{
						Vector3 velocity = componentInParent.velocity;
						Vector3 val = new Vector3(velocity.x, 0f, velocity.z);
						num = ((Vector3)(ref val)).magnitude;
					}
					componentInChildren.SetBool("Moving", num > 0.2f);
				}
			}
			catch (Exception)
			{
			}
		}

		private float GroundBelow(Vector3 from, Transform bodyOf, Transform puppet)
		{
			//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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit[] array = Physics.RaycastAll(from + Vector3.up * 2f, Vector3.down, 25f);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit[] array2 = array;
			for (int num = 0; num < array2.Length; num++)
			{
				RaycastHit val = array2[num];
				if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !(((RaycastHit)(ref val)).point.y > from.y + 0.05f) && (!((Object)(object)puppet != (Object)null) || !((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(puppet)) && (!((Object)(object)bodyOf != (Object)null) || !((Object)(object)((Component)((RaycastHit)(ref val)).collider).transform.root == (Object)(object)bodyOf.root)))
				{
					return ((RaycastHit)(ref val)).point.y;
				}
			}
			return from.y;
		}

		private static GameObject HideVisuals(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return null;
			}
			object? obj = AccessTools.Field(typeof(PlayerAvatar), "playerAvatarVisuals")?.GetValue(avatar);
			PlayerAvatarVisuals val = (PlayerAvatarVisuals)((obj is PlayerAvatarVisuals) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			((Component)val).gameObject.SetActive(false);
			return ((Component)val).gameObject;
		}

		private static string AddNoVision(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null || (Object)(object)EnemyDirector.instance == (Object)null)
			{
				return null;
			}
			string text = AccessTools.Field(typeof(PlayerAvatar), "steamID")?.GetValue(avatar) as string;
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			if (AccessTools.Field(typeof(EnemyDirector), "debugNoVision")?.GetValue(EnemyDirector.instance) is List<string> list && !list.Contains(text))
			{
				list.Add(text);
				return text;
			}
			return null;
		}

		private static void RemoveNoVision(string steamId)
		{
			if (steamId != null && !((Object)(object)EnemyDirector.instance == (Object)null))
			{
				(AccessTools.Field(typeof(EnemyDirector), "debugNoVision")?.GetValue(EnemyDirector.instance) as List<string>)?.Remove(steamId);
			}
		}

		private static PlayerAvatar FindAvatar(int actorNr)
		{
			PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>(true);
			foreach (PlayerAvatar val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.photonView != (Object)null && val.photonView.OwnerActorNr == actorNr)
				{
					return val;
				}
			}
			return null;
		}

		public void ApplyRemote(int actorNr, int setupIdx, bool on)
		{
			if (on)
			{
				if (remotes.ContainsKey(actorNr))
				{
					return;
				}
				string setupName = DisguiseItems.SetupByIndex(setupIdx);
				if ((Object)(object)DisguiseItems.FindSetup(setupName) == (Object)null)
				{
					return;
				}
				PlayerAvatar val = FindAvatar(actorNr);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Transform val2 = AcquireSourceRoot(DisguiseItems.ShortId(setupName), null);
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log("Remote disguise: no live " + DisguiseItems.ShortId(setupName) + " around");
					return;
				}
				((Component)val2).gameObject.SetActive(false);
				GameObject val3 = BuildPuppet(val2, ((Component)val).transform);
				if ((Object)(object)val3 == (Object)null)
				{
					ReleaseSourceRoot(val2);
					return;
				}
				remotes[actorNr] = new RemoteDisguise
				{
					puppet = val3,
					visuals = HideVisuals(val),
					root = val2,
					snap = CaptureSnapshot(val3),
					steamId = AddNoVision(val),
					yawOffset = ResolveYawOffset(setupName, val3)
				};
			}
			else
			{
				ClearRemote(actorNr);
			}
		}

		public void ClearRemote(int actorNr)
		{
			if (remotes.TryGetValue(actorNr, out var value))
			{
				remotes.Remove(actorNr);
				if ((Object)(object)value.puppet != (Object)null)
				{
					Object.Destroy((Object)(object)value.puppet);
				}
				if ((Object)(object)value.root != (Object)null)
				{
					ReleaseSourceRoot(value.root);
				}
				if ((Object)(object)value.visuals != (Object)null)
				{
					value.visuals.SetActive(true);
				}
				if (value.steamId != null)
				{
					RemoveNoVision(value.steamId);
				}
			}
		}

		private void ClearRemotes()
		{
			foreach (int item in new List<int>(remotes.Keys))
			{
				ClearRemote(item);
			}
		}
	}
	internal static class DisguiseItems
	{
		public const string Prefix = "Item Disguise ";

		private static bool registered;

		private static readonly Dictionary<string, string> itemToSetup = new Dictionary<string, string>();

		private static readonly List<string> setupNames = new List<string>();

		private static GameObject depot;

		private static readonly string[] prefer = new string[8] { "Tracker", "Baton", "Drone", "Orb", "Gun", "Walkie", "Mine", "Grenade" };

		private static FieldInfo itemPrefabField;

		public static IReadOnlyList<string> SetupNames => setupNames;

		public static bool IsOurs(string goName)
		{
			return goName?.StartsWith("Item Disguise ") ?? false;
		}

		public static string SetupFor(string goName)
		{
			if (goName == null)
			{
				return null;
			}
			if (itemToSetup.TryGetValue(goName, out var value))
			{
				return value;
			}
			string text = StripClone(goName);
			if (itemToSetup.TryGetValue(text, out value))
			{
				return value;
			}
			if (text.StartsWith("Item Disguise "))
			{
				string text2 = text.Substring("Item Disguise ".Length);
				foreach (KeyValuePair<string, string> item in itemToSetup)
				{
					if (ShortId(item.Value) == text2)
					{
						return item.Value;
					}
				}
			}
			return null;
		}

		public static string StripClone(string goName)
		{
			if (goName == null || !goName.EndsWith("(Clone)"))
			{
				return goName;
			}
			return goName.Substring(0, goName.Length - "(Clone)".Length);
		}

		public static int IndexOfSetup(string setupName)
		{
			return setupNames.IndexOf(setupName);
		}

		public static string SetupByIndex(int index)
		{
			if (index < 0 || index >= setupNames.Count)
			{
				return null;
			}
			return setupNames[index];
		}

		public static EnemySetup FindSetup(string setupName)
		{
			if (setupName == null)
			{
				return null;
			}
			foreach (EnemySetup allEnemy in Enemies.AllEnemies)
			{
				if ((Object)(object)allEnemy != (Object)null && ((Object)allEnemy).name == setupName)
				{
					return allEnemy;
				}
			}
			return null;
		}

		public static string ShortId(string setupName)
		{
			if (string.IsNullOrEmpty(setupName))
			{
				return "?";
			}
			int num = setupName.LastIndexOf('-');
			string text = ((num >= 0) ? setupName.Substring(num + 1) : setupName).Trim();
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return setupName;
		}

		public static string Norm(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			List<char> list = new List<char>(s.Length);
			string text = s.ToLowerInvariant();
			foreach (char c in text)
			{
				if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
				{
					list.Add(c);
				}
			}
			return new string(list.ToArray());
		}

		public static void RegisterAll()
		{
			if (registered)
			{
				return;
			}
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance == (Object)null || instance.itemDictionary == null)
			{
				return;
			}
			ItemAttributes val = PickBase(instance);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log("Disguise items: no base toggle+battery item found, retry later");
				return;
			}
			int num = 0;
			foreach (EnemySetup allEnemy in Enemies.AllEnemies)
			{
				if (!((Object)(object)allEnemy == (Object)null) && !string.IsNullOrEmpty(((Object)allEnemy).name) && RegisterOne(val, allEnemy))
				{
					num++;
				}
			}
			registered = num > 0;
			Plugin.Log($"Disguise items registered: {num} (base={((Object)((Component)val).gameObject).name})");
		}

		private static void EnsureDepot()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)depot != (Object)null))
			{
				depot = new GameObject("MonsterDisguise Depot");
				Object.DontDestroyOnLoad((Object)(object)depot);
				depot.SetActive(false);
			}
		}

		private static bool RegisterOne(ItemAttributes baseAttr, EnemySetup setup)
		{
			string text = ShortId(((Object)setup).name);
			string text2 = "Item Disguise " + text;
			if (StatsManager.instance.itemDictionary.ContainsKey(text2))
			{
				itemToSetup[text2] = ((Object)setup).name;
				if (!setupNames.Contains(((Object)setup).name))
				{
					setupNames.Add(((Object)setup).name);
				}
				return true;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)baseAttr).gameObject);
			((Object)val).name = text2;
			Object.DontDestroyOnLoad((Object)(object)val);
			ItemAttributes component = val.GetComponent<ItemAttributes>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.item == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return false;
			}
			component.item = Object.Instantiate<Item>(component.item);
			((Object)component.item).name = text2;
			component.item.itemName = text + " Disguise";
			component.item.itemNameLocalized = null;
			GameAccess.SetItemName(component, text2);
			GameAccess.SetItemValue(component, ConfigSettings.Price.Value);
			ItemBattery val2 = val.GetComponent<ItemBattery>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = val.AddComponent<ItemBattery>();
			}
			val2.batteryBars = 4;
			val2.isUnchargable = false;
			GameAccess.SetField(val2, "batteryDrainRate", 0f);
			GameAccess.SetField(val2, "autoDrain", false);
			ItemToggle val3 = val.GetComponent<ItemToggle>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val.AddComponent<ItemToggle>();
			}
			GameAccess.SetField(val3, "disabled", false);
			val3.toggleState = false;
			EnsureDepot();
			val.transform.SetParent(depot.transform, false);
			val.SetActive(true);
			try
			{
				if (Items.RegisterItem(component) == null)
				{
					Object.Destroy((Object)(object)val);
					return false;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log("RegisterItem failed for " + text2 + ": " + ex.Message);
				Object.Destroy((Object)(object)val);
				return false;
			}
			itemToSetup[text2] = ((Object)setup).name;
			if (!setupNames.Contains(((Object)setup).name))
			{
				setupNames.Add(((Object)setup).name);
			}
			return true;
		}

		private static ItemAttributes PickBase(StatsManager stats)
		{
			ItemAttributes val = null;
			ItemAttributes val2 = null;
			Dictionary<string, ItemAttributes> dictionary = new Dictionary<string, ItemAttributes>();
			foreach (Item value2 in stats.itemDictionary.Values)
			{
				if ((Object)(object)value2 == (Object)null)
				{
					continue;
				}
				GameObject val3 = PrefabOf(value2);
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				ItemAttributes component = val3.GetComponent<ItemAttributes>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)((Component)component).GetComponent<PhysGrabObject>() == (Object)null))
				{
					bool flag = (Object)(object)((Component)component).GetComponent<ItemToggle>() != (Object)null;
					bool flag2 = (Object)(object)((Component)component).GetComponent<ItemBattery>() != (Object)null;
					if (flag && flag2)
					{
						dictionary[((Object)val3).name] = component;
						val = component;
					}
					else if (flag && (Object)(object)val2 == (Object)null)
					{
						val2 = component;
					}
				}
			}
			string[] array = prefer;
			foreach (string value in array)
			{
				foreach (KeyValuePair<string, ItemAttributes> item in dictionary)
				{
					if (item.Key.Contains(value))
					{
						return item.Value;
					}
				}
			}
			return val ?? val2;
		}

		private static GameObject PrefabOf(Item item)
		{
			try
			{
				if (itemPrefabField == null)
				{
					itemPrefabField = typeof(Item).GetField("prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				object obj = itemPrefabField?.GetValue(item);
				if (obj == null)
				{
					return null;
				}
				Type type = obj.GetType();
				object? obj2 = type.GetProperty("Prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
				GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				string text = type.GetProperty("ResourcePath", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj) as string;
				return string.IsNullOrEmpty(text) ? null : Resources.Load<GameObject>(text);
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
	public class DisguiseNetworking : MonoBehaviour, IOnEventCallback
	{
		private const byte StateEvent = 81;

		private const byte ConfigEvent = 82;

		private const float ConfigBroadcastInterval = 10f;

		private bool registered;

		private float nextConfigBroadcast;

		public static DisguiseNetworking Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
		}

		private void OnDisable()
		{
			Unregister();
		}

		private static bool GameReady()
		{
			if ((Object)(object)RunManager.instance != (Object)null && (Object)(object)GameDirector.instance != (Object)null)
			{
				return SemiFunc.RunIsLevel();
			}
			return false;
		}

		private void EnsureRegistered()
		{
			if (!registered && PhotonNetwork.InRoom)
			{
				PhotonNetwork.AddCallbackTarget((object)this);
				registered = true;
			}
		}

		private void Unregister()
		{
			if (registered)
			{
				PhotonNetwork.RemoveCallbackTarget((object)this);
				registered = false;
			}
		}

		private void Update()
		{
			if (!GameReady())
			{
				Unregister();
				return;
			}
			EnsureRegistered();
			if (PhotonNetwork.IsMasterClient && Time.time >= nextConfigBroadcast)
			{
				nextConfigBroadcast = Time.time + 10f;
				BroadcastConfig();
			}
		}

		public void BroadcastState(int setupIdx, bool on)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			if (PhotonNetwork.InRoom)
			{
				int num = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1));
				if (num >= 0)
				{
					PhotonNetwork.RaiseEvent((byte)81, (object)new int[4]
					{
						81,
						num,
						setupIdx,
						on ? 1 : 0
					}, new RaiseEventOptions
					{
						Receivers = (ReceiverGroup)1
					}, SendOptions.SendReliable);
				}
			}
		}

		private static void BroadcastConfig()
		{
			//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_002f: 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_003e: Expected O, but got Unknown
			if (PhotonNetwork.InRoom)
			{
				PhotonNetwork.RaiseEvent((byte)82, (object)new int[1] { Mathf.RoundToInt(ConfigSettings.DrainPerSecond.Value * 100f) }, new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)0
				}, SendOptions.SendReliable);
			}
		}

		public void OnEvent(EventData photonEvent)
		{
			if (photonEvent != null && photonEvent.Code == 81 && photonEvent.CustomData is int[] array && array.Length >= 4)
			{
				int num = array[1];
				int num2 = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1));
				if (num != num2)
				{
					DisguiseBehavior.Instance?.ApplyRemote(num, array[2], array[3] == 1);
				}
			}
		}
	}
	internal static class GameAccess
	{
		public static T Field<T>(object target, string name)
		{
			if (target == null)
			{
				return default(T);
			}
			return (T)(AccessTools.Field(target.GetType(), name)?.GetValue(target));
		}

		public static void SetField(object target, string name, object value)
		{
			if (target != null)
			{
				AccessTools.Field(target.GetType(), name)?.SetValue(target, value);
			}
		}

		public static string ItemName(ItemAttributes attr)
		{
			return Field<string>(attr, "itemName");
		}

		public static void SetItemName(ItemAttributes attr, string value)
		{
			SetField(attr, "itemName", value);
		}

		public static int ItemValue(ItemAttributes attr)
		{
			return Field<int>(attr, "value");
		}

		public static void SetItemValue(ItemAttributes attr, int value)
		{
			SetField(attr, "value", value);
		}

		public static PhysGrabObject GrabObject(ItemAttributes attr)
		{
			PhysGrabObject obj = Field<PhysGrabObject>(attr, "physGrabObject");
			if (obj == null)
			{
				if (!((Object)(object)attr != (Object)null))
				{
					return null;
				}
				obj = ((Component)attr).GetComponent<PhysGrabObject>();
			}
			return obj;
		}

		public static bool HeldByLocal(PhysGrabObject grab)
		{
			if ((Object)(object)grab != (Object)null)
			{
				return Field<bool>(grab, "heldByLocalPlayer");
			}
			return false;
		}

		public static ItemToggle ToggleOf(ItemAttributes attr)
		{
			ItemToggle obj = Field<ItemToggle>(attr, "itemToggle");
			if (obj == null)
			{
				if (!((Object)(object)attr != (Object)null))
				{
					return null;
				}
				obj = ((Component)attr).GetComponent<ItemToggle>();
			}
			return obj;
		}
	}
	[BepInPlugin("yo.MonsterDisguise", "MonsterDisguise", "0.2.0")]
	[BepInProcess("REPO.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private static ManualLogSource logSource;

		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0025: 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_003f: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			ConfigSettings.Bind(((BaseUnityPlugin)this).Config);
			logSource = Logger.CreateLogSource("MonsterDisguise");
			new Harmony("yo.MonsterDisguise").PatchAll();
			GameObject val = new GameObject("MonsterDisguise");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<DisguiseBehavior>();
			val.AddComponent<DisguiseNetworking>();
			Log("MonsterDisguise v0.2.0 loaded");
		}

		public static void Log(string message)
		{
			logSource.LogInfo((object)message);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "yo.MonsterDisguise";

		public const string PLUGIN_NAME = "MonsterDisguise";

		public const string PLUGIN_VERSION = "0.2.0";
	}
}
namespace MonsterDisguise.Patches
{
	[HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")]
	public static class ShopPatch
	{
		[HarmonyPostfix]
		public static void RegisterDisguiseItems()
		{
			DisguiseItems.RegisterAll();
		}
	}
}