Decompiled source of MobScanner v1.0.3

BepInEx/plugin/MobScanner.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

[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("Liore")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MobScanner")]
[assembly: AssemblyTitle("MobScanner")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MobScanner
{
	[BepInPlugin("Liore.MobScanner", "MobScanner", "1.0")]
	public class MobScanner : BaseUnityPlugin
	{
		internal static ConfigEntry<bool> DebugLogging;

		internal static MobScanner Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		internal static void LogDebug(string message)
		{
			if (DebugLogging != null && DebugLogging.Value)
			{
				Logger.LogInfo((object)message);
			}
		}

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Write detailed scan, marker, preview and shop diagnostics to the log.");
			Scanner.ScanKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ScanKey", (KeyCode)122, "Hold this key to scan.");
			Scanner.HoldTime = ((BaseUnityPlugin)this).Config.Bind<float>("Scanning", "HoldTime", 3f, "How many seconds you must hold the key without moving.");
			Scanner.ScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Scanning", "ScanRadius", 20f, "How far the scan reaches, in meters. Lower = shorter range.");
			Scanner.ResultDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "ResultDuration", 15f, "How many seconds the scan results stay on screen.");
			Scanner.MarkerScale = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "MarkerScale", 1f, "Size of the dot drawn on the map. Raise this if you cannot see it.");
			Scanner.MarkerHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "MarkerHeight", 0.35f, "How far above the map surface the dot floats. Raise if dots are hidden by unexplored areas.");
			Scanner.ShowModel = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowModel", true, "Show a spinning 3D model of the monster that was found.");
			Scanner.SpinSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "SpinSpeed", 55f, "How fast the 3D model spins, in degrees per second.");
			Scanner.ModelCycleTime = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "ModelCycleTime", 2f, "Seconds each monster is shown before switching to the next one.");
			Scanner.UpgradePrice = ((BaseUnityPlugin)this).Config.Bind<float>("Shop", "UpgradePrice", 5f, "Android vision price. The shop displays thousands, so 5 shows as $5K.");
			Scanner.UsesPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "UsesPerLevel", 2, "How many successful scans you get per level. Set to 0 for unlimited.");
			Scanner.RequireUpgrade = ((BaseUnityPlugin)this).Config.Bind<bool>("Shop", "RequireUpgrade", true, "If false, scanning works without buying the upgrade (useful for testing).");
			Scanner.AlwaysInShop = ((BaseUnityPlugin)this).Config.Bind<bool>("Shop", "AlwaysInShop", false, "Force Android vision into every shop. Off by default so it turns up at random like any other upgrade.");
			Scanner.EyeEffect = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "EyeEffect", true, "Make your eyes glow while scanning. Other players can see this too.");
			Scanner.EyeFlashSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "EyeFlashSpeed", 4f, "How many times per second the eyes switch between orange and red.");
			Scanner.EyeResultTime = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "EyeResultTime", 3f, "Seconds your eyes stay pink (found) or green (clear) after a scan.");
			Scanner.FontName = ((BaseUnityPlugin)this).Config.Bind<string>("Display", "FontName", "RobotoMono", "Font for the scanner text. Tries the game's own fonts first, then fonts installed on your PC (e.g. Impact, Consolas). Leave empty to auto-pick.");
			Scanner.TextSize = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "TextSize", 22, "Size of the scanner text on screen. Raise it if the readout is hard to see.");
			Scanner.OutlineThickness = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "OutlineThickness", 1.5f, "Thickness of the dark outline behind the text. Set to 0 to turn it off.");
			Scanner.UseCustomCardArt = ((BaseUnityPlugin)this).Config.Bind<bool>("Shop", "UseCustomCardArt", true, "Paint the mod's own artwork onto the Android vision shop card.");
			Scanner.HudX = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "HudX", 0.015f, "Left edge of the scanner readout, as a fraction of screen width. 0 = far left, 0.5 = centre.");
			Scanner.HudY = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "HudY", 0.44f, "Top of the scanner readout, as a fraction of screen height. 0 = top, 1 = bottom.");
			Scanner.ExportCardTemplate = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ExportCardTemplate", false, "Developer tool: save the shop card's texture to disk so it can be used as a painting template.");
			Scanner.Cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Scanning", "Cooldown", 3f, "Seconds you must wait after a scan before you can scan again.");
			((Component)this).gameObject.AddComponent<Scanner>();
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
			bool flag = false;
			foreach (MethodBase patchedMethod in Harmony.GetPatchedMethods())
			{
				if (patchedMethod != null && patchedMethod.DeclaringType != null && patchedMethod.DeclaringType.Name == "ItemUpgradePlayerGrabStrength")
				{
					flag = true;
					break;
				}
			}
			Logger.LogInfo((object)$"PATCH CHECK: ItemUpgradePlayerGrabStrength.Upgrade hooked = {flag}");
		}

		internal void Patch()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public class ModelPreview
	{
		private GameObject? _root;

		private Camera? _camera;

		private RenderTexture? _texture;

		private const int PreviewLayer = 31;

		private static readonly Vector3 StageOrigin = new Vector3(0f, -5000f, 0f);

		public bool IsValid => (Object)(object)_root != (Object)null && (Object)(object)_texture != (Object)null;

		public RenderTexture? Texture => _texture;

		public bool Build(EnemyParent enemyParent, int size)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0077: 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)
			//IL_008e: Expected O, but got Unknown
			//IL_00ae: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_045f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f8: Expected O, but got Unknown
			//IL_0527: Unknown result type (might be due to invalid IL or missing references)
			//IL_057a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Expected O, but got Unknown
			//IL_05b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0603: Unknown result type (might be due to invalid IL or missing references)
			//IL_060d: Expected O, but got Unknown
			//IL_061e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0625: Expected O, but got Unknown
			//IL_0654: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_070c: Unknown result type (might be due to invalid IL or missing references)
			Dispose();
			if ((Object)(object)enemyParent == (Object)null || (Object)(object)enemyParent.Enemy == (Object)null)
			{
				return false;
			}
			GameObject val = (((Object)(object)enemyParent.EnableObject != (Object)null) ? enemyParent.EnableObject : ((Component)enemyParent).gameObject);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			try
			{
				_root = new GameObject("MobScanner Preview Root");
				_root.transform.position = StageOrigin;
				GameObject val2 = new GameObject("Model");
				val2.transform.SetParent(_root.transform, false);
				val2.transform.localPosition = Vector3.zero;
				bool activeSelf = val.activeSelf;
				val.SetActive(false);
				GameObject val3 = Object.Instantiate<GameObject>(val, val2.transform);
				val.SetActive(activeSelf);
				((Object)val3).name = "ModelBody";
				val3.transform.localRotation = Quaternion.identity;
				val3.transform.localScale = Vector3.one;
				StripToVisualsOnly(val3);
				SetLayerRecursive(_root, 31);
				val3.SetActive(true);
				int num = 0;
				Transform[] componentsInChildren = val3.GetComponentsInChildren<Transform>(true);
				foreach (Transform val4 in componentsInChildren)
				{
					if (!((Component)val4).gameObject.activeSelf)
					{
						num++;
					}
				}
				if (num > 0)
				{
					MobScanner.LogDebug($"PREVIEW: left {num} hidden part(s) hidden");
				}
				Bounds val5 = CalculateBounds(val3);
				float num2 = Mathf.Max(new float[3]
				{
					((Bounds)(ref val5)).size.x,
					((Bounds)(ref val5)).size.y,
					((Bounds)(ref val5)).size.z
				});
				if (num2 <= 0.001f)
				{
					num2 = 1f;
				}
				float num3 = 2f / num2;
				if (num3 < 0.25f || num3 > 6f)
				{
					MobScanner.Logger.LogWarning((object)($"PREVIEW: measured size {((Bounds)(ref val5)).size} gives an unusable scale " + $"{num3:F2} - clamping. The model may look off."));
					num3 = Mathf.Clamp(num3, 0.25f, 6f);
				}
				Renderer[] componentsInChildren2 = val3.GetComponentsInChildren<Renderer>(true);
				Vector3 size2 = ((Bounds)(ref val5)).size;
				float num4 = Mathf.Max(((Vector3)(ref size2)).magnitude * 3f, 6f);
				int num5 = 0;
				int num6 = 0;
				Renderer[] array = componentsInChildren2;
				foreach (Renderer val6 in array)
				{
					Bounds bounds = val6.bounds;
					Vector3 size3 = ((Bounds)(ref bounds)).size;
					float num7 = Mathf.Max(size3.x, Mathf.Max(size3.y, size3.z));
					bounds = val6.bounds;
					bool flag = Vector3.Distance(((Bounds)(ref bounds)).center, ((Bounds)(ref val5)).center) > num4;
					bool flag2 = num7 > 25f;
					if (flag || flag2)
					{
						val6.enabled = false;
						num5++;
					}
					else
					{
						num6++;
					}
				}
				if (num6 == 0)
				{
					Renderer[] array2 = componentsInChildren2;
					foreach (Renderer val7 in array2)
					{
						val7.enabled = true;
					}
					num5 = 0;
					num6 = componentsInChildren2.Length;
					MobScanner.LogDebug("PREVIEW: filter emptied model - restored all");
				}
				MobScanner.LogDebug($"PREVIEW: hid {num5}, showing {num6}");
				int num8 = 0;
				Renderer[] array3 = componentsInChildren2;
				foreach (Renderer val8 in array3)
				{
					if (val8.enabled)
					{
						num8++;
					}
				}
				if (num8 == 0)
				{
					MobScanner.Logger.LogWarning((object)"PREVIEW: nothing is visible - the preview box will be empty");
				}
				else
				{
					MobScanner.LogDebug($"PREVIEW: {num8} part(s) actually visible");
				}
				val3.transform.localScale = Vector3.one * num3;
				Bounds val9 = CalculateBounds(val3);
				Vector3 val10 = ((Bounds)(ref val9)).center - val2.transform.position;
				val3.transform.localPosition = -val10;
				MobScanner.LogDebug("PREVIEW: source=" + ((Object)val).name + " " + $"renderers={val3.GetComponentsInChildren<Renderer>(true).Length} " + $"skinned={val3.GetComponentsInChildren<SkinnedMeshRenderer>(true).Length} " + $"size={((Bounds)(ref val5)).size} fitScale={num3:F2}");
				GameObject val11 = new GameObject("Key Light");
				val11.transform.SetParent(_root.transform, false);
				val11.transform.localPosition = new Vector3(2f, 2.5f, -3f);
				val11.layer = 31;
				Light val12 = val11.AddComponent<Light>();
				val12.type = (LightType)2;
				val12.range = 40f;
				val12.intensity = 6f;
				val12.cullingMask = int.MinValue;
				GameObject val13 = new GameObject("Fill Light");
				val13.transform.SetParent(_root.transform, false);
				val13.transform.localPosition = new Vector3(-2.5f, 1f, -2f);
				val13.layer = 31;
				Light val14 = val13.AddComponent<Light>();
				val14.type = (LightType)2;
				val14.range = 40f;
				val14.intensity = 3f;
				val14.cullingMask = int.MinValue;
				_texture = new RenderTexture(size, size, 16);
				_texture.Create();
				GameObject val15 = new GameObject("Preview Camera");
				val15.transform.SetParent(_root.transform, false);
				val15.transform.localPosition = new Vector3(0f, 0f, -4f);
				val15.layer = 31;
				_camera = val15.AddComponent<Camera>();
				_camera.cullingMask = int.MinValue;
				_camera.clearFlags = (CameraClearFlags)2;
				_camera.backgroundColor = new Color(0.04f, 0.05f, 0.04f, 1f);
				_camera.targetTexture = _texture;
				_camera.fieldOfView = 40f;
				_camera.nearClipPlane = 0.05f;
				_camera.farClipPlane = 100f;
				val15.transform.LookAt(val2.transform.position);
				((Behaviour)_camera).enabled = true;
				Object.DontDestroyOnLoad((Object)(object)_root);
				return true;
			}
			catch (Exception ex)
			{
				MobScanner.Logger.LogWarning((object)("PREVIEW: failed to build - " + ex.Message));
				Dispose();
				return false;
			}
		}

		private static void StripToVisualsOnly(GameObject model)
		{
			for (int i = 0; i < 4; i++)
			{
				MonoBehaviour[] componentsInChildren = model.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null))
					{
						try
						{
							Object.DestroyImmediate((Object)(object)val);
						}
						catch (Exception)
						{
						}
					}
				}
			}
			Component[] componentsInChildren2 = model.GetComponentsInChildren<Component>(true);
			foreach (Component val2 in componentsInChildren2)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				string name = ((object)val2).GetType().Name;
				if (name.Contains("Photon") || name.Contains("NavMesh"))
				{
					try
					{
						Object.DestroyImmediate((Object)(object)val2);
					}
					catch (Exception)
					{
					}
				}
			}
			Collider[] componentsInChildren3 = model.GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren3)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val3);
				}
			}
			Rigidbody[] componentsInChildren4 = model.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val4 in componentsInChildren4)
			{
				if ((Object)(object)val4 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val4);
				}
			}
			Animator[] componentsInChildren5 = model.GetComponentsInChildren<Animator>(true);
			foreach (Animator val5 in componentsInChildren5)
			{
				if ((Object)(object)val5 != (Object)null)
				{
					((Behaviour)val5).enabled = false;
				}
			}
			ParticleSystem[] componentsInChildren6 = model.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val6 in componentsInChildren6)
			{
				if ((Object)(object)val6 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val6);
				}
			}
			AudioSource[] componentsInChildren7 = model.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource val7 in componentsInChildren7)
			{
				if ((Object)(object)val7 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val7);
				}
			}
			Light[] componentsInChildren8 = model.GetComponentsInChildren<Light>(true);
			foreach (Light val8 in componentsInChildren8)
			{
				if ((Object)(object)val8 != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val8);
				}
			}
		}

		private static Bounds CalculateBounds(GameObject model)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0616: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: 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_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0593: Unknown result type (might be due to invalid IL or missing references)
			//IL_0595: Unknown result type (might be due to invalid IL or missing references)
			//IL_050d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0512: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0523: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Unknown result type (might be due to invalid IL or missing references)
			//IL_0612: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0604: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = model.GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren.Length == 0)
			{
				return new Bounds(model.transform.position, Vector3.one);
			}
			List<Renderer> list = new List<Renderer>();
			List<float> list2 = new List<float>();
			Renderer[] array = componentsInChildren;
			Bounds bounds;
			foreach (Renderer val in array)
			{
				bounds = val.bounds;
				Vector3 size = ((Bounds)(ref bounds)).size;
				if (!(size.y < 0.02f) || (!(size.x > 5f) && !(size.z > 5f)))
				{
					float num = Mathf.Max(size.x, Mathf.Max(size.y, size.z));
					if (!(num > 25f))
					{
						list.Add(val);
						list2.Add(num);
					}
				}
			}
			if (list.Count == 0)
			{
				Bounds bounds2 = componentsInChildren[0].bounds;
				for (int j = 1; j < componentsInChildren.Length; j++)
				{
					((Bounds)(ref bounds2)).Encapsulate(componentsInChildren[j].bounds);
				}
				return bounds2;
			}
			List<float> list3 = new List<float>(list2);
			list3.Sort();
			float num2 = list3[list3.Count / 2];
			float num3 = Mathf.Max(num2 * 4f, 1.5f);
			Renderer val2 = list[0];
			int num4 = -1;
			for (int k = 0; k < list.Count; k++)
			{
				bounds = list[k].bounds;
				Vector3 center = ((Bounds)(ref bounds)).center;
				int num5 = 0;
				for (int l = 0; l < list.Count; l++)
				{
					bounds = list[l].bounds;
					if (Vector3.Distance(((Bounds)(ref bounds)).center, center) <= 3f)
					{
						num5++;
					}
				}
				if (num5 > num4)
				{
					num4 = num5;
					val2 = list[k];
				}
			}
			bounds = val2.bounds;
			Vector3 center2 = ((Bounds)(ref bounds)).center;
			MobScanner.LogDebug("PREVIEW: anchored on '" + ((Object)((Component)val2).gameObject).name + "' " + $"with {num4} neighbour(s) of {list.Count} candidates");
			bool flag = false;
			Bounds bounds3 = default(Bounds);
			((Bounds)(ref bounds3))..ctor(model.transform.position, Vector3.zero);
			int num6 = 0;
			int num7 = 0;
			for (int m = 0; m < list.Count; m++)
			{
				if (list2[m] > num3)
				{
					continue;
				}
				bounds = list[m].bounds;
				if (Vector3.Distance(((Bounds)(ref bounds)).center, center2) > 3f)
				{
					num7++;
					continue;
				}
				if (!flag)
				{
					bounds3 = list[m].bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref bounds3)).Encapsulate(list[m].bounds);
				}
				num6++;
			}
			if (num6 < list.Count / 3 && list.Count >= 12)
			{
				MobScanner.LogDebug($"PREVIEW: cluster too small ({num6}/{list.Count}) - measuring all parts");
				bounds3 = list[0].bounds;
				for (int n = 1; n < list.Count; n++)
				{
					((Bounds)(ref bounds3)).Encapsulate(list[n].bounds);
				}
				num6 = list.Count;
				num7 = 0;
			}
			if (num7 > 0)
			{
				MobScanner.LogDebug($"PREVIEW: ignored {num7} scattered parts");
				string text = "";
				string text2 = "";
				int num8 = 0;
				int num9 = 0;
				for (int num10 = 0; num10 < list.Count; num10++)
				{
					int num11;
					if (list2[num10] <= num3)
					{
						bounds = list[num10].bounds;
						num11 = ((Vector3.Distance(((Bounds)(ref bounds)).center, center2) <= 3f) ? 1 : 0);
					}
					else
					{
						num11 = 0;
					}
					bool flag2 = (byte)num11 != 0;
					if (flag2 && num8 < 5)
					{
						text = text + ((Object)((Component)list[num10]).gameObject).name + ", ";
						num8++;
					}
					else if (!flag2 && num9 < 5)
					{
						text2 = text2 + ((Object)((Component)list[num10]).gameObject).name + ", ";
						num9++;
					}
				}
				MobScanner.LogDebug("PREVIEW: kept e.g. " + text);
				MobScanner.LogDebug("PREVIEW: dropped e.g. " + text2);
			}
			if (!flag)
			{
				bounds3 = list[0].bounds;
				for (int num12 = 1; num12 < list.Count; num12++)
				{
					((Bounds)(ref bounds3)).Encapsulate(list[num12].bounds);
				}
				num6 = list.Count;
			}
			MobScanner.LogDebug($"PREVIEW: measured {num6}/{componentsInChildren.Length} parts, median={num2:F2}, limit={num3:F2}");
			Vector3 size2 = ((Bounds)(ref bounds3)).size;
			if (size2.x < 0.1f || size2.y < 0.1f || size2.z < 0.1f)
			{
				((Bounds)(ref bounds3)).Encapsulate(((Bounds)(ref bounds3)).center + Vector3.one * 0.25f);
				((Bounds)(ref bounds3)).Encapsulate(((Bounds)(ref bounds3)).center - Vector3.one * 0.25f);
			}
			return bounds3;
		}

		private static void SetLayerRecursive(GameObject target, int layer)
		{
			target.layer = layer;
			Transform[] componentsInChildren = target.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				((Component)val).gameObject.layer = layer;
			}
		}

		public void Spin(float degreesPerSecond)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root == (Object)null))
			{
				Transform val = _root.transform.Find("Model");
				if ((Object)(object)val != (Object)null)
				{
					val.Rotate(Vector3.up, degreesPerSecond * Time.deltaTime, (Space)0);
				}
			}
		}

		public void Dispose()
		{
			if ((Object)(object)_camera != (Object)null)
			{
				_camera.targetTexture = null;
				_camera = null;
			}
			if ((Object)(object)_texture != (Object)null)
			{
				_texture.Release();
				Object.Destroy((Object)(object)_texture);
				_texture = null;
			}
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
				_root = null;
			}
		}
	}
	public class ScanResult
	{
		public string Name = "";

		public int Tier = 1;

		public int Count = 1;

		public Transform? EnemyTransform;

		public EnemyParent? Parent;

		public GameObject? Marker;
	}
	public class Scanner : MonoBehaviour
	{
		public static ConfigEntry<KeyCode> ScanKey = null;

		public static ConfigEntry<float> ScanRadius = null;

		public static ConfigEntry<float> HoldTime = null;

		public static ConfigEntry<float> ResultDuration = null;

		public static ConfigEntry<float> MarkerScale = null;

		public static ConfigEntry<float> Cooldown = null;

		public static ConfigEntry<float> MarkerHeight = null;

		public static ConfigEntry<bool> ShowModel = null;

		public static ConfigEntry<float> SpinSpeed = null;

		public static ConfigEntry<float> ModelCycleTime = null;

		public static ConfigEntry<float> UpgradePrice = null;

		public static ConfigEntry<int> UsesPerLevel = null;

		public static ConfigEntry<bool> RequireUpgrade = null;

		public static ConfigEntry<bool> AlwaysInShop = null;

		public static ConfigEntry<bool> EyeEffect = null;

		public static ConfigEntry<float> EyeFlashSpeed = null;

		public static ConfigEntry<float> EyeResultTime = null;

		public static ConfigEntry<string> FontName = null;

		public static ConfigEntry<int> TextSize = null;

		public static ConfigEntry<bool> UseCustomCardArt = null;

		public static ConfigEntry<bool> ExportCardTemplate = null;

		public static ConfigEntry<float> HudX = null;

		public static ConfigEntry<float> HudY = null;

		public static ConfigEntry<float> OutlineThickness = null;

		private float _holdTimer;

		private bool _scanning;

		private bool _awaitingRelease;

		private readonly List<ScanResult> _results = new List<ScanResult>();

		private float _resultTimer;

		private float _cooldownTimer;

		private bool _foundAnything;

		private static bool _hasScanner;

		private static int _usesLeft;

		private readonly ModelPreview _preview = new ModelPreview();

		private int _previewIndex;

		private float _previewTimer;

		private string _previewName = "";

		private float _eyeFlashTimer;

		private bool _eyeUseRed;

		private float _eyeResultTimer;

		private bool _eyeResultFound;

		private float _shopRegisterTimer;

		private float _networkSyncTimer;

		private Texture2D? _dotTexture;

		private static readonly Color TierGreen = new Color(0.2f, 1f, 0.2f);

		private static readonly Color TierOrange = new Color(1f, 0.65f, 0f);

		private static readonly Color TierRed = new Color(1f, 0.15f, 0.15f);

		private string _lastLevelName = "";

		private float _messageTimer;

		private string _message = "";

		private static Font? _gameFont;

		private static bool _fontSearched;

		private static Font? GameFont
		{
			get
			{
				EnsureFont();
				return _gameFont;
			}
		}

		public static void GrantScanner()
		{
			_hasScanner = true;
		}

		public static bool HasScanner()
		{
			if (_hasScanner)
			{
				return true;
			}
			Dictionary<string, int> dictionary = ShopIntegration.Ownership();
			if (dictionary == null)
			{
				return false;
			}
			PlayerAvatar instance = PlayerAvatar.instance;
			if ((Object)(object)instance == (Object)null || string.IsNullOrEmpty(instance.steamID))
			{
				return false;
			}
			int value;
			return dictionary.TryGetValue(instance.steamID, out value) && value > 0;
		}

		private static Color ColourForTier(int tier)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (tier >= 3)
			{
				return TierRed;
			}
			if (tier == 2)
			{
				return TierOrange;
			}
			return TierGreen;
		}

		private void Awake()
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			_dotTexture = new Texture2D(1, 1);
			_dotTexture.SetPixel(0, 0, Color.white);
			_dotTexture.Apply();
		}

		private void Update()
		{
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ShopIntegration.RegisteredItem == (Object)null)
			{
				_shopRegisterTimer -= Time.deltaTime;
				if (_shopRegisterTimer <= 0f)
				{
					_shopRegisterTimer = 1f;
					ShopIntegration.TryRegister();
				}
			}
			_networkSyncTimer -= Time.deltaTime;
			if (_networkSyncTimer <= 0f)
			{
				_networkSyncTimer = 1f;
				ShopIntegration.SyncNetworkedItems();
			}
			UpdateMarkers();
			if (_resultTimer > 0f)
			{
				_preview.Spin(SpinSpeed.Value);
				if (_previewTimer > 0f)
				{
					_previewTimer -= Time.deltaTime;
					if (_previewTimer <= 0f)
					{
						ShowNextPreview();
					}
				}
			}
			if (_resultTimer > 0f)
			{
				_resultTimer -= Time.deltaTime;
				if (_resultTimer <= 0f)
				{
					ClearResults();
				}
			}
			if (_cooldownTimer > 0f)
			{
				_cooldownTimer -= Time.deltaTime;
			}
			if (_messageTimer > 0f)
			{
				_messageTimer -= Time.deltaTime;
			}
			if ((Object)(object)Map.Instance == (Object)null || (Object)(object)PlayerController.instance == (Object)null)
			{
				_eyeResultTimer = 0f;
				return;
			}
			if (_eyeResultTimer > 0f)
			{
				_eyeResultTimer -= Time.deltaTime;
				ShowResultEyes();
			}
			string levelKey = GetLevelKey();
			if (levelKey != _lastLevelName)
			{
				MobScanner.LogDebug("SCAN: level changed '" + _lastLevelName + "' -> '" + levelKey + "'");
				_lastLevelName = levelKey;
				_usesLeft = UsesPerLevel.Value;
				ShopIntegration.ResetNetworkList();
				ClearResults();
				MobScanner.LogDebug($"SCAN: uses reset to {_usesLeft}");
			}
			if (RequireUpgrade.Value && !HasScanner())
			{
				return;
			}
			if (_cooldownTimer > 0f)
			{
				_scanning = false;
				_holdTimer = 0f;
			}
			else if (UsesPerLevel.Value > 0 && _usesLeft <= 0)
			{
				if (Input.GetKeyDown(ScanKey.Value))
				{
					_message = "NO SCANS LEFT";
					_messageTimer = 2f;
				}
				_scanning = false;
				_holdTimer = 0f;
			}
			else if (!Input.GetKey(ScanKey.Value))
			{
				if (_scanning)
				{
					MobScanner.LogDebug("SCAN: cancelled (key released)");
				}
				_scanning = false;
				_holdTimer = 0f;
				_awaitingRelease = false;
			}
			else
			{
				if (_awaitingRelease)
				{
					return;
				}
				if (!_scanning)
				{
					_scanning = true;
					_holdTimer = 0f;
					MobScanner.LogDebug("SCAN: started - charging...");
					return;
				}
				UpdateEyeEffect();
				_holdTimer += Time.deltaTime;
				if (!(_holdTimer >= HoldTime.Value))
				{
					return;
				}
				_scanning = false;
				_holdTimer = 0f;
				_awaitingRelease = true;
				DoScan();
				_eyeResultFound = _foundAnything;
				_eyeResultTimer = EyeResultTime.Value;
				if (_foundAnything)
				{
					_cooldownTimer = Cooldown.Value;
					if (UsesPerLevel.Value > 0)
					{
						_usesLeft--;
						MobScanner.LogDebug($"SCAN: use consumed - {_usesLeft} left this level");
					}
					else
					{
						MobScanner.LogDebug("SCAN: unlimited mode - no use consumed");
					}
				}
				else
				{
					MobScanner.LogDebug("SCAN: nothing found - use NOT consumed");
				}
			}
		}

		private static void EnsureFont()
		{
			if (_fontSearched)
			{
				return;
			}
			_fontSearched = true;
			Font[] array = Resources.FindObjectsOfTypeAll<Font>();
			MobScanner.LogDebug($"FONT: {array.Length} font(s) loaded in memory");
			Font[] array2 = array;
			foreach (Font val in array2)
			{
				if ((Object)(object)val != (Object)null)
				{
					MobScanner.LogDebug("FONT: available '" + ((Object)val).name + "'");
				}
			}
			string text = FontName.Value ?? "";
			if (text.Length > 0)
			{
				Font[] array3 = array;
				foreach (Font val2 in array3)
				{
					if ((Object)(object)val2 != (Object)null && ((Object)val2).name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						_gameFont = val2;
						MobScanner.LogDebug("FONT: using '" + ((Object)val2).name + "' (loaded in game)");
						return;
					}
				}
				try
				{
					string[] oSInstalledFontNames = Font.GetOSInstalledFontNames();
					MobScanner.LogDebug($"FONT: {oSInstalledFontNames.Length} font(s) installed on this machine");
					string[] array4 = oSInstalledFontNames;
					foreach (string text2 in array4)
					{
						if (text2 != null && text2.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)
						{
							Font val3 = Font.CreateDynamicFontFromOSFont(text2, 18);
							if ((Object)(object)val3 != (Object)null)
							{
								_gameFont = val3;
								MobScanner.Logger.LogInfo((object)("FONT: using '" + text2 + "' from this PC. Players without it will see the default font instead."));
								return;
							}
						}
					}
				}
				catch (Exception ex)
				{
					MobScanner.Logger.LogWarning((object)("FONT: could not read installed fonts - " + ex.Message));
				}
				MobScanner.Logger.LogWarning((object)("FONT: nothing matching '" + text + "' - falling back to the default"));
				return;
			}
			string[] array5 = new string[7] { "pixel", "silk", "vcr", "press", "arcade", "8bit", "bit" };
			string[] array6 = array5;
			foreach (string text3 in array6)
			{
				Font[] array7 = array;
				foreach (Font val4 in array7)
				{
					if ((Object)(object)val4 != (Object)null && ((Object)val4).name.IndexOf(text3, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						_gameFont = val4;
						MobScanner.LogDebug("FONT: auto-picked '" + ((Object)val4).name + "' (hint '" + text3 + "')");
						return;
					}
				}
			}
			MobScanner.LogDebug("FONT: no pixel font found - using Unity's default");
		}

		private void UpdateEyeEffect()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if (!EyeEffect.Value)
			{
				return;
			}
			PlayerAvatar playerAvatarScript = PlayerController.instance.playerAvatarScript;
			if (!((Object)(object)playerAvatarScript == (Object)null) && !((Object)(object)playerAvatarScript.playerHealth == (Object)null))
			{
				_eyeFlashTimer -= Time.deltaTime;
				if (_eyeFlashTimer <= 0f)
				{
					_eyeFlashTimer = 1f / Mathf.Max(EyeFlashSpeed.Value, 0.1f);
					_eyeUseRed = !_eyeUseRed;
				}
				EyeOverrideState val = (EyeOverrideState)(_eyeUseRed ? 1 : 4);
				playerAvatarScript.playerHealth.EyeMaterialOverride(val, 0.25f, 2);
			}
		}

		private void ShowResultEyes()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (EyeEffect.Value && !((Object)(object)PlayerController.instance == (Object)null))
			{
				PlayerAvatar playerAvatarScript = PlayerController.instance.playerAvatarScript;
				if (!((Object)(object)playerAvatarScript == (Object)null) && !((Object)(object)playerAvatarScript.playerHealth == (Object)null))
				{
					EyeOverrideState val = (EyeOverrideState)(_eyeResultFound ? 3 : 2);
					playerAvatarScript.playerHealth.EyeMaterialOverride(val, 0.25f, 3);
				}
			}
		}

		private static string GetLevelKey()
		{
			RunManager instance = RunManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return "no-run";
			}
			string arg = (((Object)(object)instance.levelCurrent != (Object)null) ? ((Object)instance.levelCurrent).name : "null");
			return $"{arg}|{instance.levelsCompleted}|{instance.runLives}";
		}

		private List<ScanResult> UniqueResults()
		{
			List<ScanResult> list = new List<ScanResult>();
			foreach (ScanResult result in _results)
			{
				if (result.Count > 0)
				{
					list.Add(result);
				}
			}
			return list;
		}

		private void ShowNextPreview()
		{
			if (ShowModel.Value)
			{
				List<ScanResult> list = UniqueResults();
				if (list.Count <= 1)
				{
					_previewTimer = ModelCycleTime.Value;
					return;
				}
				_previewIndex = (_previewIndex + 1) % list.Count;
				BuildPreviewFor(list[_previewIndex]);
			}
		}

		private void BuildPreviewFor(ScanResult result)
		{
			if (!((Object)(object)result.Parent == (Object)null))
			{
				if (_preview.IsValid && _previewName == result.Name)
				{
					_previewTimer = ModelCycleTime.Value;
					return;
				}
				bool flag = _preview.Build(result.Parent, 220);
				_previewName = result.Name;
				_previewTimer = ModelCycleTime.Value;
				MobScanner.LogDebug("PREVIEW: showing " + result.Name + " (" + (flag ? "ok" : "failed") + ")");
			}
		}

		private void ClearResults()
		{
			foreach (ScanResult result in _results)
			{
				if ((Object)(object)result.Marker != (Object)null)
				{
					Object.Destroy((Object)(object)result.Marker);
				}
			}
			_results.Clear();
			_preview.Dispose();
			_previewIndex = 0;
			_previewTimer = 0f;
			_previewName = "";
		}

		private void UpdateMarkers()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Map.Instance == (Object)null)
			{
				return;
			}
			foreach (ScanResult result in _results)
			{
				if (!((Object)(object)result.Marker == (Object)null) && !((Object)(object)result.EnemyTransform == (Object)null))
				{
					Transform transform = result.Marker.transform;
					Vector3 val = result.EnemyTransform.position * Map.Instance.Scale + Map.Instance.OverLayerParent.position;
					transform.position = new Vector3(val.x, Map.Instance.OverLayerParent.position.y + MarkerHeight.Value, val.z);
					float num = Mathf.PingPong(Time.time * 2.2f, 1f);
					Color val2 = ColourForTier(result.Tier);
					Color color = Color.Lerp(val2, Color.white, num * 0.55f);
					color.a = 0.55f + num * 0.45f;
					SpriteRenderer[] componentsInChildren = result.Marker.GetComponentsInChildren<SpriteRenderer>(true);
					foreach (SpriteRenderer val3 in componentsInChildren)
					{
						val3.color = color;
					}
					float num2 = MarkerScale.Value * (1f + num * 0.35f);
					transform.localScale = Vector3.one * num2;
				}
			}
		}

		private GameObject? CreateMarker(Transform enemyTransform, Color colour)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Map.Instance == (Object)null)
			{
				return null;
			}
			GameObject val = (((Object)(object)Map.Instance.ValuableObject != (Object)null) ? Map.Instance.ValuableObject : Map.Instance.EnemyObject);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, Map.Instance.OverLayerParent);
			((Object)val2).name = "MobScanner Marker";
			val2.SetActive(true);
			MapValuable component = val2.GetComponent<MapValuable>();
			if ((Object)(object)component != (Object)null)
			{
				SpriteRenderer spriteRenderer = component.spriteRenderer;
				if ((Object)(object)spriteRenderer != (Object)null && (Object)(object)spriteRenderer.sprite == (Object)null)
				{
					spriteRenderer.sprite = (((Object)(object)component.spriteBig != (Object)null) ? component.spriteBig : component.spriteSmall);
				}
				Object.Destroy((Object)(object)component);
			}
			val2.transform.localScale = Vector3.one * MarkerScale.Value;
			SpriteRenderer[] componentsInChildren = val2.GetComponentsInChildren<SpriteRenderer>(true);
			foreach (SpriteRenderer val3 in componentsInChildren)
			{
				val3.color = colour;
				((Renderer)val3).enabled = true;
				((Renderer)val3).sortingOrder = 32000;
			}
			Transform[] componentsInChildren2 = val2.GetComponentsInChildren<Transform>(true);
			foreach (Transform val4 in componentsInChildren2)
			{
				((Component)val4).gameObject.SetActive(true);
				((Component)val4).gameObject.layer = ((Component)Map.Instance.OverLayerParent).gameObject.layer;
			}
			MobScanner.LogDebug($"MARKER: built from {((Object)val).name}, scale={MarkerScale.Value}");
			return val2;
		}

		private void DoScan()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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_0195: Expected I4, but got Unknown
			//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_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			MobScanner.LogDebug("=== SCAN COMPLETE ===");
			ClearResults();
			_resultTimer = ResultDuration.Value;
			Vector3 position = ((Component)PlayerController.instance).transform.position;
			List<RoomVolume> list = new List<RoomVolume>();
			PlayerAvatar playerAvatarScript = PlayerController.instance.playerAvatarScript;
			if ((Object)(object)playerAvatarScript != (Object)null && (Object)(object)playerAvatarScript.RoomVolumeCheck != (Object)null)
			{
				list.AddRange(playerAvatarScript.RoomVolumeCheck.CurrentRooms);
			}
			foreach (EnemyParent item in EnemyDirector.instance.enemiesSpawned)
			{
				if ((Object)(object)item == (Object)null || (Object)(object)item.Enemy == (Object)null || !item.Spawned || (item.Enemy.HasHealth && item.Enemy.Health.dead))
				{
					continue;
				}
				Vector3 position2 = ((Component)item.Enemy).transform.position;
				float num = Vector3.Distance(position, position2);
				if (num > ScanRadius.Value)
				{
					continue;
				}
				bool flag = false;
				foreach (RoomVolume currentRoom in item.currentRooms)
				{
					if ((Object)(object)currentRoom != (Object)null && list.Contains(currentRoom))
					{
						flag = true;
						break;
					}
				}
				int num2 = item.difficulty + 1;
				Color colour = ColourForTier(num2);
				ScanResult scanResult = null;
				foreach (ScanResult result in _results)
				{
					if (result.Name == item.enemyName)
					{
						scanResult = result;
						break;
					}
				}
				if (scanResult != null)
				{
					scanResult.Count++;
					scanResult.Marker = scanResult.Marker;
					GameObject val = CreateMarker(((Component)item.Enemy).transform, colour);
					if ((Object)(object)val != (Object)null)
					{
						_results.Add(new ScanResult
						{
							Name = item.enemyName,
							Tier = num2,
							Count = 0,
							EnemyTransform = ((Component)item.Enemy).transform,
							Parent = item,
							Marker = val
						});
					}
					MobScanner.LogDebug($"SCAN: found {item.enemyName} | T{num2} | {num:F1}m | " + (flag ? "SAME ROOM" : "nearby room"));
				}
				else
				{
					ScanResult scanResult2 = new ScanResult
					{
						Name = item.enemyName,
						Tier = num2,
						EnemyTransform = ((Component)item.Enemy).transform,
						Parent = item
					};
					scanResult2.Marker = CreateMarker(((Component)item.Enemy).transform, colour);
					if ((Object)(object)scanResult2.Marker == (Object)null)
					{
						MobScanner.Logger.LogWarning((object)"SCAN: could not create map marker");
					}
					_results.Add(scanResult2);
					MobScanner.LogDebug($"SCAN: found {item.enemyName} | T{num2} | {num:F1}m | " + (flag ? "SAME ROOM" : "nearby room"));
				}
			}
			_foundAnything = _results.Count > 0;
			if (_foundAnything && ShowModel.Value)
			{
				List<ScanResult> list2 = UniqueResults();
				if (list2.Count > 0)
				{
					_previewIndex = 0;
					BuildPreviewFor(list2[0]);
				}
			}
			if (_results.Count == 0)
			{
				MobScanner.LogDebug("SCAN: no monsters in range");
			}
			MobScanner.LogDebug("=====================");
		}

		private static Vector2 HudOrigin()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2((float)Screen.width * HudX.Value, (float)Screen.height * HudY.Value);
		}

		private static float LineHeight()
		{
			return (float)TextSize.Value * 1.8f;
		}

		private void DrawLabel(Rect rect, string text, GUIStyle style, Color colour)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_003d: 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_006e: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			float value = OutlineThickness.Value;
			if (value > 0f)
			{
				GUIStyle val = new GUIStyle(style);
				val.normal.textColor = new Color(0f, 0f, 0f, 0.85f * colour.a);
				GUI.Label(new Rect(((Rect)(ref rect)).x - value, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, val);
				GUI.Label(new Rect(((Rect)(ref rect)).x + value, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, val);
				GUI.Label(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y - value, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, val);
				GUI.Label(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y + value, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, val);
			}
			GUIStyle val2 = new GUIStyle(style);
			val2.normal.textColor = colour;
			GUI.Label(rect, text, val2);
		}

		private void DrawRect(float x, float y, float width, float height, Color colour)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_dotTexture == (Object)null))
			{
				Color color = GUI.color;
				GUI.color = colour;
				GUI.DrawTexture(new Rect(x, y, width, height), (Texture)(object)_dotTexture);
				GUI.color = color;
			}
		}

		private void DrawDot(float x, float y, float size, Color colour)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			if (!((Object)(object)_dotTexture == (Object)null))
			{
				Color color = GUI.color;
				GUI.color = colour;
				GUI.DrawTexture(new Rect(x, y, size, size), (Texture)(object)_dotTexture);
				GUI.color = color;
			}
		}

		private void OnGUI()
		{
			//IL_006b: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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)
			//IL_00cf: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Expected O, but got Unknown
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Expected O, but got Unknown
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0634: Unknown result type (might be due to invalid IL or missing references)
			//IL_063b: Expected O, but got Unknown
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_066f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0659: Unknown result type (might be due to invalid IL or missing references)
			//IL_068b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0521: Unknown result type (might be due to invalid IL or missing references)
			//IL_056b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Unknown result type (might be due to invalid IL or missing references)
			//IL_057c: Unknown result type (might be due to invalid IL or missing references)
			//IL_058f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0597: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Expected O, but got Unknown
			//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0626: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0703: Unknown result type (might be due to invalid IL or missing references)
			//IL_072e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0737: Unknown result type (might be due to invalid IL or missing references)
			//IL_073e: Expected O, but got Unknown
			//IL_0745: Unknown result type (might be due to invalid IL or missing references)
			//IL_075e: Unknown result type (might be due to invalid IL or missing references)
			//IL_077b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0784: Unknown result type (might be due to invalid IL or missing references)
			//IL_078b: Expected O, but got Unknown
			//IL_0792: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Map.Instance == (Object)null || (Object)(object)PlayerController.instance == (Object)null || SemiFunc.MenuLevel())
			{
				return;
			}
			if (_messageTimer > 0f && _message != "")
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					font = GameFont,
					fontSize = TextSize.Value,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				val.normal.textColor = new Color(1f, 0.4f, 0.3f);
				Vector2 val2 = HudOrigin();
				DrawLabel(new Rect(val2.x, val2.y, 360f, LineHeight()), _message, val, new Color(1f, 0.4f, 0.3f));
			}
			if (!RequireUpgrade.Value || HasScanner())
			{
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					font = GameFont,
					fontSize = TextSize.Value - 2,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				val3.normal.textColor = ((UsesPerLevel.Value <= 0 || _usesLeft > 0) ? new Color(0.4f, 1f, 0.5f, 0.85f) : new Color(0.7f, 0.3f, 0.3f, 0.85f));
				string text = ((UsesPerLevel.Value > 0) ? $"SCANS: {_usesLeft}" : "SCANS: UNLIMITED");
				Vector2 val4 = HudOrigin();
				DrawLabel(new Rect(val4.x, val4.y - LineHeight(), 360f, LineHeight()), text, val3, val3.normal.textColor);
			}
			Vector2 val5 = HudOrigin();
			float x = val5.x;
			float y = val5.y;
			if (_scanning)
			{
				float num = _holdTimer / HoldTime.Value;
				float num2 = 4f + num * 8f;
				float num3 = Mathf.PingPong(Time.time * num2, 1f);
				float num4 = 0.35f + num3 * 0.65f;
				DrawDot(x, y + LineHeight() * 0.5f - 5f, 11f, new Color(0.2f, 1f, 0.2f, num4));
				GUIStyle val6 = new GUIStyle(GUI.skin.label)
				{
					font = GameFont,
					fontSize = TextSize.Value,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				val6.normal.textColor = new Color(0.2f, 1f, 0.2f, num4);
				DrawLabel(new Rect(x + 20f, y, 360f, LineHeight()), "SCANNING...", val6, new Color(0.2f, 1f, 0.2f, num4));
			}
			else
			{
				if (_resultTimer <= 0f)
				{
					return;
				}
				GUIStyle val7 = new GUIStyle(GUI.skin.label)
				{
					font = GameFont,
					fontSize = TextSize.Value,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				if (_preview.IsValid && (Object)(object)_preview.Texture != (Object)null)
				{
					float num5 = Mathf.Clamp((float)Screen.height * 0.16f, 110f, 320f);
					float num6 = Mathf.Max(3f, num5 * 0.027f);
					float num7 = y - num5 - 12f;
					float x2 = x - num6;
					float y2 = num7 - num6;
					float num8 = num5 + num6 * 2f;
					DrawRect(x2, y2, num8, num8, new Color(0.58f, 0.6f, 0.57f, 0.95f));
					DrawRect(x - 1f, num7 - 1f, num5 + 2f, num5 + 2f, new Color(0.08f, 0.1f, 0.08f, 1f));
					DrawRect(x, num7, num5, num5, new Color(0.07f, 0.13f, 0.09f, 1f));
					GUI.DrawTexture(new Rect(x, num7, num5, num5), (Texture)(object)_preview.Texture);
					Color colour = default(Color);
					((Color)(ref colour))..ctor(0f, 0f, 0f, 0.14f);
					for (float num9 = 1f; num9 < num5 - 1f; num9 += 4f)
					{
						DrawRect(x, num7 + num9, num5, 2f, colour);
					}
					List<ScanResult> list = UniqueResults();
					if (list.Count > 1)
					{
						GUIStyle val8 = new GUIStyle(GUI.skin.label)
						{
							font = GameFont,
							fontSize = TextSize.Value - 4,
							fontStyle = (FontStyle)1,
							alignment = (TextAnchor)5
						};
						val8.normal.textColor = new Color(0.5f, 1f, 0.6f, 0.85f);
						float num10 = LineHeight();
						DrawLabel(new Rect(x, num7 + num5 - num10 - 4f, num5 - 6f, num10), $"{_previewIndex + 1}/{list.Count}", val8, new Color(0.5f, 1f, 0.6f, 0.85f));
					}
				}
				GUIStyle val9 = new GUIStyle(val7);
				val9.normal.textColor = (_foundAnything ? new Color(0.2f, 1f, 0.2f) : new Color(0.75f, 0.75f, 0.75f));
				float num11 = LineHeight();
				DrawLabel(new Rect(x, y, 360f, num11), _foundAnything ? "FOUND" : "NOT FOUND", val9, val9.normal.textColor);
				float num12 = y + num11 + 2f;
				int num13 = 0;
				for (int i = 0; i < _results.Count; i++)
				{
					ScanResult scanResult = _results[i];
					if (scanResult.Count > 0)
					{
						Color val10 = ColourForTier(scanResult.Tier);
						float num14 = num12 + (float)num13 * num11;
						num13++;
						DrawDot(x, num14 + num11 * 0.5f - 5f, 11f, val10);
						GUIStyle val11 = new GUIStyle(val7);
						val11.normal.textColor = val10;
						DrawLabel(new Rect(x + 22f, num14, 44f, num11), $"T{scanResult.Tier}", val11, val10);
						GUIStyle val12 = new GUIStyle(val7);
						val12.normal.textColor = Color.white;
						string text2 = ((scanResult.Count > 1) ? $"{scanResult.Name}  x{scanResult.Count}" : scanResult.Name);
						DrawLabel(new Rect(x + 66f, num14, 300f, num11), text2, val12, Color.white);
					}
				}
			}
		}

		private void OnDestroy()
		{
			ClearResults();
		}
	}
	public class MobScannerItemTag : MonoBehaviour
	{
	}
	public static class ShopIntegration
	{
		public const string ItemKey = "Item Upgrade Android Vision";

		public const string DisplayName = "Android vision";

		private const string TemplateKey = "Item Upgrade Player Grab Strength";

		internal static Item? RegisteredItem;

		public const string NetworkKey = "MobScannerItems";

		private static readonly List<int> _publishedIDs = new List<int>();

		public const string OwnershipKey = "playerUpgradeAndroidVision";

		private static Texture2D? _cardArt;

		private static bool _cardArtChecked;

		internal static void PublishOurItem(ItemAttributes attributes)
		{
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				PhotonView component = ((Component)attributes).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null || component.ViewID == 0)
				{
					MobScanner.LogDebug("NET: converted item has no network ID yet - not published");
				}
				else if (!_publishedIDs.Contains(component.ViewID))
				{
					_publishedIDs.Add(component.ViewID);
					SemiFunc.SetCurrentRoomProperty("MobScannerItems", (object)_publishedIDs.ToArray());
					MobScanner.LogDebug($"NET: published item {component.ViewID} ({_publishedIDs.Count} total this level)");
				}
			}
		}

		internal static void SyncNetworkedItems()
		{
			if (!SemiFunc.IsMultiplayer() || PhotonNetwork.CurrentRoom == null)
			{
				return;
			}
			Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
			if (customProperties == null || !((Dictionary<object, object>)(object)customProperties).ContainsKey((object)"MobScannerItems") || !(customProperties[(object)"MobScannerItems"] is int[] array))
			{
				return;
			}
			Item registeredItem = RegisteredItem;
			if ((Object)(object)registeredItem == (Object)null)
			{
				return;
			}
			int[] array2 = array;
			foreach (int num in array2)
			{
				PhotonView val = PhotonView.Find(num);
				if (!((Object)(object)val == (Object)null))
				{
					ItemAttributes component = ((Component)val).GetComponent<ItemAttributes>();
					if (!((Object)(object)component == (Object)null) && !((Object)(object)((Component)component).GetComponent<MobScannerItemTag>() != (Object)null))
					{
						((Component)component).gameObject.AddComponent<MobScannerItemTag>();
						component.item = registeredItem;
						component.itemName = "Android vision";
						component.value = (int)Scanner.UpgradePrice.Value;
						ApplyCardArt(((Component)component).gameObject);
						MobScanner.LogDebug($"NET: applied host's Android vision to item {num}");
					}
				}
			}
		}

		internal static void ResetNetworkList()
		{
			_publishedIDs.Clear();
		}

		private static Texture2D? CardArt()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			if (_cardArtChecked)
			{
				return _cardArt;
			}
			_cardArtChecked = true;
			try
			{
				string location = Assembly.GetExecutingAssembly().Location;
				string path = Path.GetDirectoryName(location) ?? "";
				string text = Path.Combine(path, "card.png");
				if (!File.Exists(text))
				{
					MobScanner.Logger.LogWarning((object)("CARD ART: no card.png next to the mod (" + text + ") - keeping the default art"));
					return null;
				}
				byte[] array = File.ReadAllBytes(text);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
				if (!ImageConversion.LoadImage(val, array))
				{
					MobScanner.Logger.LogWarning((object)"CARD ART: card.png could not be read as an image");
					Object.Destroy((Object)(object)val);
					return null;
				}
				((Object)val).name = "MobScanner Card Art";
				Object.DontDestroyOnLoad((Object)(object)val);
				_cardArt = val;
				MobScanner.Logger.LogInfo((object)$"CARD ART: loaded card.png ({((Texture)val).width}x{((Texture)val).height})");
			}
			catch (Exception ex)
			{
				MobScanner.Logger.LogWarning((object)("CARD ART: could not load card.png - " + ex.Message));
			}
			return _cardArt;
		}

		internal static void ApplyCardArt(GameObject card)
		{
			if (!Scanner.UseCustomCardArt.Value)
			{
				return;
			}
			Texture2D val = CardArt();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int num = 0;
			Renderer[] componentsInChildren = card.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				Material[] materials = val2.materials;
				foreach (Material val3 in materials)
				{
					if (!((Object)(object)val3 == (Object)null) && val3.HasProperty("_MainTex"))
					{
						Texture texture = val3.GetTexture("_MainTex");
						if (!((Object)(object)texture == (Object)null) && ((Object)texture).name.StartsWith("Upgrade_"))
						{
							val3.SetTexture("_MainTex", (Texture)(object)val);
							num++;
						}
					}
				}
			}
			if (num > 0)
			{
				MobScanner.LogDebug($"CARD ART: painted {num} surface(s)");
			}
			else
			{
				MobScanner.Logger.LogWarning((object)"CARD ART: found no card face to paint");
			}
		}

		public static Dictionary<string, int>? Ownership()
		{
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if (!instance.dictionaryOfDictionaries.TryGetValue("playerUpgradeAndroidVision", out var value))
			{
				value = new Dictionary<string, int>();
				instance.dictionaryOfDictionaries.Add("playerUpgradeAndroidVision", value);
				MobScanner.LogDebug("SHOP: created Android vision ownership store");
			}
			return value;
		}

		public static void TryRegister()
		{
			//IL_01d1: 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_00e4: Invalid comparison between Unknown and I4
			if ((Object)(object)RegisteredItem != (Object)null || (Object)(object)StatsManager.instance == (Object)null)
			{
				return;
			}
			Dictionary<string, Item> itemDictionary = StatsManager.instance.itemDictionary;
			if (itemDictionary.Count == 0)
			{
				return;
			}
			if (itemDictionary.ContainsKey("Item Upgrade Android Vision"))
			{
				RegisteredItem = itemDictionary["Item Upgrade Android Vision"];
				return;
			}
			MobScanner.LogDebug($"SHOP: item dictionary has {itemDictionary.Count} entries, registering...");
			Item val = null;
			if (itemDictionary.ContainsKey("Item Upgrade Player Grab Strength"))
			{
				val = itemDictionary["Item Upgrade Player Grab Strength"];
			}
			else
			{
				foreach (KeyValuePair<string, Item> item in itemDictionary)
				{
					if ((Object)(object)item.Value != (Object)null && (int)item.Value.itemType == 3)
					{
						val = item.Value;
						MobScanner.LogDebug("SHOP: template 'Item Upgrade Player Grab Strength' missing, using '" + item.Key + "'");
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				MobScanner.Logger.LogWarning((object)"SHOP: no upgrade template found - cannot register");
				return;
			}
			Item val2 = Object.Instantiate<Item>(val);
			((Object)val2).name = "Item Upgrade Android Vision";
			val2.itemName = "Android vision";
			val2.itemNameLocalized = null;
			val2.value.valueMin = 2000f;
			val2.value.valueMax = 2000f;
			val2.maxAmountInShop = 1;
			Object.DontDestroyOnLoad((Object)(object)val2);
			itemDictionary["Item Upgrade Android Vision"] = val2;
			RegisteredItem = val2;
			MobScanner.LogDebug("SHOP: registered 'Android vision' (template=" + ((Object)val).name + ", " + $"type={val2.itemType})");
		}
	}
	[HarmonyPatch(typeof(StatsManager))]
	internal static class StatsManagerPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("LoadItemsFromFolder")]
		private static void LoadItemsFromFolder_Postfix()
		{
			ShopIntegration.TryRegister();
		}
	}
	[HarmonyPatch(typeof(ShopManager), "UpgradeValueGet")]
	internal static class UpgradeValueGetPatch
	{
		private static void Postfix(Item item, ref float __result)
		{
			if ((Object)(object)item != (Object)null && ((Object)item).name == "Item Upgrade Android Vision")
			{
				__result = Scanner.UpgradePrice.Value;
			}
		}
	}
	[HarmonyPatch(typeof(ShopManager), "GetAllItemsFromStatsManager")]
	internal static class ForceIntoPoolPatch
	{
		private static void Postfix(ShopManager __instance)
		{
			if (!Scanner.AlwaysInShop.Value)
			{
				return;
			}
			Item registeredItem = ShopIntegration.RegisteredItem;
			if (!((Object)(object)registeredItem == (Object)null))
			{
				int num = __instance.potentialItemUpgrades.RemoveAll((Item x) => (Object)(object)x != (Object)null && ((Object)x).name == "Item Upgrade Android Vision");
				__instance.potentialItemUpgrades.Add(registeredItem);
				MobScanner.LogDebug("SHOP POOL: moved Android vision to the end of the queue " + $"(removed {num} stray copies, {__instance.potentialItemUpgrades.Count} upgrades total, " + $"shop shows {__instance.itemUpgradesAmount})");
			}
		}
	}
	[HarmonyPatch(typeof(ShopManager), "GetAllItemsFromStatsManager")]
	internal static class ShopPoolPatch
	{
		private static void Postfix(ShopManager __instance)
		{
			int count = __instance.potentialItemUpgrades.Count;
			int num = 0;
			foreach (Item potentialItemUpgrade in __instance.potentialItemUpgrades)
			{
				if ((Object)(object)potentialItemUpgrade != (Object)null && ((Object)potentialItemUpgrade).name == "Item Upgrade Android Vision")
				{
					num++;
				}
			}
			MobScanner.LogDebug($"SHOP POOL: {count} upgrades available, {num} of them are Android vision");
			for (int i = 0; i < __instance.potentialItemUpgrades.Count; i++)
			{
				Item val = __instance.potentialItemUpgrades[i];
				if ((Object)(object)val != (Object)null && ((Object)val).name == "Item Upgrade Android Vision")
				{
					MobScanner.LogDebug($"SHOP POOL: Android vision is at position {i} " + $"(shop displays the first {__instance.itemUpgradesAmount})");
					break;
				}
			}
			if (num == 0)
			{
				MobScanner.LogDebug("SHOP POOL: Android vision was filtered out - checking why...");
				if ((Object)(object)ShopIntegration.RegisteredItem == (Object)null)
				{
					MobScanner.LogDebug("SHOP POOL: reason = item never registered");
					return;
				}
				Item registeredItem = ShopIntegration.RegisteredItem;
				int num2 = SemiFunc.StatGetItemsPurchased(((Object)registeredItem).name);
				MobScanner.LogDebug($"SHOP POOL: purchased={num2} " + $"maxAmountInShop={registeredItem.maxAmountInShop} " + $"maxPurchase={registeredItem.maxPurchase} " + $"minPlayerCount={registeredItem.minPlayerCount} " + $"valueMax={registeredItem.value.valueMax} " + $"currency={__instance.totalCurrency}");
			}
		}
	}
	[HarmonyPatch(typeof(PunManager), "SpawnShopItem")]
	internal static class SpawnShopItemPatch
	{
		private static void Postfix(ItemVolume itemVolume, List<Item> itemList, bool __result)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (!__result)
			{
				return;
			}
			bool flag = false;
			foreach (Item item in itemList)
			{
				if ((Object)(object)item != (Object)null && ((Object)item).name == "Item Upgrade Android Vision")
				{
					flag = true;
					break;
				}
			}
			MobScanner.LogDebug($"SHOP SPAWN: placed an item on a '{itemVolume.itemVolume}' shelf, " + $"{itemList.Count} left in this list, ours still queued: {flag}");
		}
	}
	[HarmonyPatch(typeof(PunManager), "ShopPopulateItemVolumes")]
	internal static class ShelfCheckPatch
	{
		private static void Prefix()
		{
			//IL_0052: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			Item registeredItem = ShopIntegration.RegisteredItem;
			if ((Object)(object)registeredItem == (Object)null || (Object)(object)ShopManager.instance == (Object)null)
			{
				return;
			}
			int num = 0;
			foreach (ItemVolume itemVolume in ShopManager.instance.itemVolumes)
			{
				if ((Object)(object)itemVolume != (Object)null && itemVolume.itemVolume == registeredItem.itemVolume)
				{
					num++;
				}
			}
			MobScanner.LogDebug($"SHOP SHELVES: Android vision needs a '{registeredItem.itemVolume}' shelf; " + $"{num} of {ShopManager.instance.itemVolumes.Count} shelves match. " + "prefab=" + ((registeredItem.prefab == null) ? "NULL" : ((PrefabRef<GameObject>)(object)registeredItem.prefab).ResourcePath));
		}
	}
	[HarmonyPatch(typeof(ItemAttributes), "Start")]
	internal static class ItemAttributesStartPatch
	{
		internal static int PendingSpawns;

		internal static bool CardInspected;

		private static void InspectCard(GameObject card)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_008e: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			MobScanner.Logger.LogInfo((object)"=== CARD INSPECTION ===");
			Renderer[] componentsInChildren = card.GetComponentsInChildren<Renderer>(true);
			MobScanner.Logger.LogInfo((object)$"CARD: {componentsInChildren.Length} renderer(s)");
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Renderer val = componentsInChildren[i];
				Bounds bounds = val.bounds;
				Vector3 size = ((Bounds)(ref bounds)).size;
				MobScanner.Logger.LogInfo((object)($"CARD[{i}] object='{((Object)((Component)val).gameObject).name}' " + $"type={((object)val).GetType().Name} size=({size.x:F2},{size.y:F2},{size.z:F2}) " + $"materials={val.materials.Length}"));
				for (int j = 0; j < val.materials.Length; j++)
				{
					Material val2 = val.materials[j];
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					string text = (((Object)(object)val2.shader != (Object)null) ? ((Object)val2.shader).name : "none");
					string text2 = "none";
					if (val2.HasProperty("_MainTex"))
					{
						Texture texture = val2.GetTexture("_MainTex");
						text2 = (((Object)(object)texture != (Object)null) ? $"{((Object)texture).name} ({texture.width}x{texture.height})" : "empty");
					}
					MobScanner.Logger.LogInfo((object)$"CARD[{i}] material[{j}]='{((Object)val2).name}' shader='{text}' mainTex={text2}");
					if (Scanner.ExportCardTemplate.Value && val2.HasProperty("_MainTex"))
					{
						Texture texture2 = val2.GetTexture("_MainTex");
						if ((Object)(object)texture2 != (Object)null && texture2.width > 64)
						{
							DumpTexture(texture2, $"CardTemplate_{i}_{j}");
						}
					}
				}
			}
			ItemAttributes component = card.GetComponent<ItemAttributes>();
			if ((Object)(object)component != (Object)null)
			{
				MobScanner.Logger.LogInfo((object)("CARD: icon=" + (((Object)(object)component.icon != (Object)null) ? ((Object)component.icon).name : "none") + " " + $"hasIcon={component.hasIcon}"));
			}
			MobScanner.Logger.LogInfo((object)"=======================");
		}

		private static void DumpTexture(Texture source, string label)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0);
				Graphics.Blit(source, temporary);
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(source.width, source.height, (TextureFormat)5, false);
				val.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0);
				val.Apply();
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
				string text = Path.Combine(Paths.PluginPath, "MobScanner");
				Directory.CreateDirectory(text);
				string text2 = Path.Combine(text, label + "_" + ((Object)source).name + ".png");
				File.WriteAllBytes(text2, ImageConversion.EncodeToPNG(val));
				Object.Destroy((Object)(object)val);
				MobScanner.Logger.LogInfo((object)("CARD: saved texture to " + text2));
			}
			catch (Exception ex)
			{
				MobScanner.Logger.LogWarning((object)("CARD: could not save texture - " + ex.Message));
			}
		}

		private static void Postfix(ItemAttributes __instance)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			Item registeredItem = ShopIntegration.RegisteredItem;
			if ((Object)(object)registeredItem == (Object)null || (Object)(object)__instance.item == (Object)null)
			{
				return;
			}
			if ((int)__instance.item.itemType == 3)
			{
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				int num = (((Object)(object)component != (Object)null) ? component.ViewID : (-1));
				MobScanner.LogDebug($"UPGRADE SPAWN: item='{((Object)__instance.item).name}' viewID={num} " + $"value={__instance.value} pending={PendingSpawns} " + $"master={SemiFunc.IsMasterClientOrSingleplayer()}");
			}
			if (!((Object)(object)((Component)__instance).GetComponent<MobScannerItemTag>() == (Object)null))
			{
				__instance.item = registeredItem;
				__instance.itemName = "Android vision";
				__instance.value = (int)Scanner.UpgradePrice.Value;
				ShopIntegration.ApplyCardArt(((Component)__instance).gameObject);
				ShopIntegration.PublishOurItem(__instance);
				if (!CardInspected)
				{
					CardInspected = true;
					InspectCard(((Component)__instance).gameObject);
				}
				PhotonView component2 = ((Component)__instance).GetComponent<PhotonView>();
				MobScanner.LogDebug($"SHOP: CONVERTED viewID={(((Object)(object)component2 != (Object)null) ? component2.ViewID : (-1))} " + string.Format("into '{0}' at value {1}", "Android vision", __instance.value));
			}
		}
	}
	[HarmonyPatch(typeof(PunManager), "SpawnShopItem")]
	internal static class ShopSpawnMarkPatch
	{
		private static void Prefix(ItemVolume itemVolume, List<Item> itemList)
		{
			//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)
			if ((Object)(object)ShopIntegration.RegisteredItem == (Object)null || (Object)(object)itemVolume == (Object)null)
			{
				return;
			}
			for (int num = itemList.Count - 1; num >= 0; num--)
			{
				Item val = itemList[num];
				if (!((Object)(object)val == (Object)null) && val.itemVolume == itemVolume.itemVolume)
				{
					if (((Object)val).name == "Item Upgrade Android Vision")
					{
						ItemAttributesStartPatch.PendingSpawns++;
						MobScanner.LogDebug("SPAWN MARK: Android vision is the next shop spawn");
					}
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemAttributes), "Awake")]
	internal static class ItemAttributesAwakePatch
	{
		private static void Postfix(ItemAttributes __instance)
		{
			if (ItemAttributesStartPatch.PendingSpawns > 0)
			{
				ItemAttributesStartPatch.PendingSpawns--;
				if ((Object)(object)((Component)__instance).GetComponent<MobScannerItemTag>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<MobScannerItemTag>();
				}
				MobScanner.LogDebug("SPAWN CLAIM: tagged '" + ((Object)((Component)__instance).gameObject).name + "' as Android vision");
			}
		}
	}
	[HarmonyPatch(typeof(PunManager), "SpawnItem")]
	internal static class TruckSpawnMarkPatch
	{
		private static void Prefix(Item item)
		{
			if ((Object)(object)item != (Object)null && ((Object)item).name == "Item Upgrade Android Vision")
			{
				ItemAttributesStartPatch.PendingSpawns++;
				MobScanner.LogDebug("SPAWN MARK: Android vision is the next truck spawn");
			}
		}
	}
	[HarmonyPatch(typeof(ItemUpgradePlayerGrabStrength), "Upgrade")]
	internal static class GrabStrengthUpgradePatch
	{
		private static bool Prefix(ItemUpgradePlayerGrabStrength __instance)
		{
			ItemAttributes component = ((Component)__instance).GetComponent<ItemAttributes>();
			bool flag = (Object)(object)((Component)__instance).GetComponent<MobScannerItemTag>() != (Object)null;
			string text = (((Object)(object)component != (Object)null && (Object)(object)component.item != (Object)null) ? ((Object)component.item).name : "none");
			MobScanner.Logger.LogInfo((object)$"UPGRADE HOOK: grab-strength upgrade used. tagged={flag} item='{text}'");
			if (!flag && text != "Item Upgrade Android Vision")
			{
				return true;
			}
			ItemToggle component2 = ((Component)__instance).GetComponent<ItemToggle>();
			PlayerAvatar val = (((Object)(object)component2 != (Object)null) ? SemiFunc.PlayerAvatarGetFromPhotonID(component2.playerTogglePhotonID) : null);
			if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.steamID))
			{
				MobScanner.LogDebug("UPGRADE: Android vision used but the player is unknown");
				return false;
			}
			Dictionary<string, int> dictionary = ShopIntegration.Ownership();
			if (dictionary != null)
			{
				dictionary[val.steamID] = 1;
			}
			if (val.isLocal)
			{
				Scanner.GrantScanner();
			}
			MobScanner.LogDebug("UPGRADE: Android vision granted to " + val.playerName + " " + $"({val.steamID}), local={val.isLocal} - grab strength skipped");
			return false;
		}
	}
	[HarmonyPatch(typeof(StatsManager), "AddItemsUpgradesPurchased")]
	internal static class UpgradePurchasedPatch
	{
		private static void Postfix(string itemName)
		{
			if (!(itemName != "Item Upgrade Android Vision"))
			{
				MobScanner.LogDebug("SHOP: Android vision purchase recorded");
			}
		}
	}
}