Decompiled source of LookWhatIGot v1.0.0

LookWhatIGot.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using LookWhatIGot.Patches;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Rendering;

[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: AssemblyCompany("LookWhatIGot")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LookWhatIGot")]
[assembly: AssemblyTitle("LookWhatIGot")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace LookWhatIGot
{
	public static class HoldingLabelManager
	{
		private const bool UseAnchorLayer = false;

		private const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static FieldInfo grabbedObjectField;

		private static FieldInfo valueField;

		private static Font labelFont;

		private static bool initialized;

		private static readonly Dictionary<Transform, GameObject> labels = new Dictionary<Transform, GameObject>();

		private static PhysGrabObject lastGrabbed;

		private static float nextCleanup;

		private static readonly HashSet<string> UselessNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"Rigidbody", "Physics", "Mesh", "Model", "Object", "Collider", "Colliders", "Body", "Root", "Visuals",
			"Graphics"
		};

		private static readonly HashSet<string> LevelPrefixes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"Museum", "Manor", "Wizard", "Arena", "Arctic", "Swamp", "Mansion", "Hotel", "Space", "Lab",
			"Fight", "Level", "Generic", "Valuable"
		};

		private static bool OnlyShowValuables => LookWhatIGotPlugin.CfgOnlyShowValuables?.Value ?? true;

		private static bool DebugPinToCamera => LookWhatIGotPlugin.CfgDebugPinToCamera?.Value ?? false;

		private static float LabelHeight => LookWhatIGotPlugin.CfgLabelHeight?.Value ?? 2.3f;

		private static int LabelLayer => LookWhatIGotPlugin.CfgLabelLayer?.Value ?? 0;

		public static void Initialize()
		{
			if (!initialized)
			{
				initialized = true;
				CacheFont();
				CacheReflection();
			}
		}

		private static void CacheFont()
		{
			string[] array = new string[2] { "LegacyRuntime.ttf", "Arial.ttf" };
			foreach (string text in array)
			{
				try
				{
					labelFont = Resources.GetBuiltinResource<Font>(text);
					if ((Object)(object)labelFont != (Object)null)
					{
						LookWhatIGotPlugin.Dbg("Using builtin font: " + text);
						return;
					}
				}
				catch (Exception)
				{
				}
			}
			labelFont = Font.CreateDynamicFontFromOSFont("Arial", 32);
			if ((Object)(object)labelFont == (Object)null)
			{
				LookWhatIGotPlugin.Log.LogError((object)"No font found - labels will be invisible.");
			}
			else
			{
				LookWhatIGotPlugin.Dbg("Using OS font: Arial");
			}
		}

		private static void CacheReflection()
		{
			FieldInfo[] fields = typeof(PhysGrabber).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (typeof(PhysGrabObject).IsAssignableFrom(fieldInfo.FieldType))
				{
					grabbedObjectField = fieldInfo;
					LookWhatIGotPlugin.Dbg("Grabbed-object field: " + fieldInfo.Name);
					break;
				}
			}
			if (grabbedObjectField == null)
			{
				LookWhatIGotPlugin.Log.LogError((object)"No PhysGrabObject field on PhysGrabber!");
				DumpFields(typeof(PhysGrabber));
			}
			string[] array = new string[3] { "dollarValueCurrent", "dollarValue", "valueCurrent" };
			string[] array2 = array;
			foreach (string name in array2)
			{
				valueField = typeof(ValuableObject).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (valueField != null)
				{
					LookWhatIGotPlugin.Dbg("Value field: " + valueField.Name);
					break;
				}
			}
			if (valueField == null)
			{
				FieldInfo[] fields2 = typeof(ValuableObject).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo2 in fields2)
				{
					string text = fieldInfo2.Name.ToLowerInvariant();
					if ((fieldInfo2.FieldType == typeof(float) || fieldInfo2.FieldType == typeof(int)) && (text.Contains("dollar") || text.Contains("value")))
					{
						valueField = fieldInfo2;
						LookWhatIGotPlugin.Dbg("Value field (fallback): " + fieldInfo2.Name);
						break;
					}
				}
			}
			if (valueField == null)
			{
				LookWhatIGotPlugin.Log.LogWarning((object)"No value field on ValuableObject.");
				DumpFields(typeof(ValuableObject));
			}
		}

		private static void DumpFields(Type t)
		{
			StringBuilder stringBuilder = new StringBuilder("--- fields on " + t.Name + " ---\n");
			FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				stringBuilder.AppendLine("  " + fieldInfo.FieldType.Name + " " + fieldInfo.Name);
			}
			LookWhatIGotPlugin.Log.LogInfo((object)stringBuilder.ToString());
		}

		public static void Tick(PhysGrabber grabber)
		{
			PhysGrabObject grabbedObject = GetGrabbedObject(grabber);
			if ((Object)(object)grabbedObject != (Object)(object)lastGrabbed)
			{
				OnLocalGrabChanged(grabbedObject);
				lastGrabbed = grabbedObject;
			}
			UpdateBillboards();
			PeriodicCleanup();
		}

		private static void OnLocalGrabChanged(PhysGrabObject grabbedObj)
		{
			Transform val = ResolveLocalAnchor();
			ValuableObject val2 = (((Object)(object)grabbedObj != (Object)null) ? FindValuable(grabbedObj) : null);
			if ((Object)(object)grabbedObj == (Object)null || (OnlyShowValuables && (Object)(object)val2 == (Object)null))
			{
				if ((Object)(object)val != (Object)null)
				{
					HideLabel(val);
				}
				LabelNetwork.BroadcastHide();
				return;
			}
			string itemName = CleanItemName(grabbedObj, val2);
			int value = ReadValue(val2);
			if ((Object)(object)val != (Object)null)
			{
				ShowLabel(val, itemName, value);
			}
			LabelNetwork.BroadcastShow(itemName, value);
		}

		private static PhysGrabObject GetGrabbedObject(PhysGrabber grabber)
		{
			if (grabbedObjectField == null)
			{
				return null;
			}
			object? value = grabbedObjectField.GetValue(grabber);
			return (PhysGrabObject)((value is PhysGrabObject) ? value : null);
		}

		private static ValuableObject FindValuable(PhysGrabObject obj)
		{
			ValuableObject component = ((Component)obj).GetComponent<ValuableObject>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			return ((Component)obj).GetComponentInParent<ValuableObject>();
		}

		private static string CleanItemName(PhysGrabObject obj, ValuableObject valuable)
		{
			string text = (((Object)(object)valuable != (Object)null) ? ((Object)((Component)valuable).gameObject).name : ((Object)((Component)obj).gameObject).name);
			text = text.Replace("(Clone)", "").Trim();
			if (UselessNames.Contains(text))
			{
				Transform parent = ((Component)obj).transform.parent;
				while ((Object)(object)parent != (Object)null)
				{
					string text2 = ((Object)parent).name.Replace("(Clone)", "").Trim();
					if (!UselessNames.Contains(text2))
					{
						text = text2;
						break;
					}
					parent = parent.parent;
				}
			}
			text = SplitPascalCase(text);
			string[] array = text.Split(new char[3] { ' ', '_', '-' }, StringSplitOptions.RemoveEmptyEntries);
			int i;
			for (i = 0; i < array.Length - 1 && LevelPrefixes.Contains(array[i]); i++)
			{
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int j = i; j < array.Length; j++)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(TitleCaseWord(array[j]));
			}
			string text3 = stringBuilder.ToString().Trim();
			return (text3.Length > 0) ? text3 : text;
		}

		private static string SplitPascalCase(string s)
		{
			StringBuilder stringBuilder = new StringBuilder(s.Length + 8);
			for (int i = 0; i < s.Length; i++)
			{
				if (i > 0 && char.IsUpper(s[i]) && !char.IsUpper(s[i - 1]) && s[i - 1] != ' ')
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(s[i]);
			}
			return stringBuilder.ToString();
		}

		private static string TitleCaseWord(string w)
		{
			if (w.Length == 0)
			{
				return w;
			}
			if (w.Length <= 3 && w.ToUpperInvariant() == w)
			{
				return w;
			}
			return char.ToUpper(w[0], CultureInfo.InvariantCulture) + w.Substring(1).ToLowerInvariant();
		}

		private static int ReadValue(ValuableObject valuable)
		{
			if ((Object)(object)valuable == (Object)null || valueField == null)
			{
				return 0;
			}
			object value = valueField.GetValue(valuable);
			if (value is float num)
			{
				return Mathf.RoundToInt(num);
			}
			if (value is int result)
			{
				return result;
			}
			return 0;
		}

		private static Transform ResolveLocalAnchor()
		{
			if (DebugPinToCamera)
			{
				Camera camera = GetCamera();
				return ((Object)(object)camera != (Object)null) ? ((Component)camera).transform : null;
			}
			PhysGrabber instance = PhysGrabber.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			PlayerAvatar componentInParent = ((Component)instance).GetComponentInParent<PlayerAvatar>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return ((Component)componentInParent).transform;
			}
			return ((Component)instance).transform.root;
		}

		internal static Camera GetCamera()
		{
			if ((Object)(object)Camera.main != (Object)null)
			{
				return Camera.main;
			}
			if ((Object)(object)Camera.current != (Object)null)
			{
				return Camera.current;
			}
			return (Camera.allCamerasCount > 0) ? Camera.allCameras[0] : null;
		}

		private static void UpdateBillboards()
		{
			//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_0071: Unknown result type (might be due to invalid IL or missing references)
			if (labels.Count == 0 || DebugPinToCamera)
			{
				return;
			}
			Camera camera = GetCamera();
			if ((Object)(object)camera == (Object)null)
			{
				return;
			}
			Quaternion rotation = ((Component)camera).transform.rotation;
			foreach (KeyValuePair<Transform, GameObject> label in labels)
			{
				if ((Object)(object)label.Value != (Object)null)
				{
					label.Value.transform.rotation = rotation;
				}
			}
		}

		private static void PeriodicCleanup()
		{
			if (Time.time < nextCleanup)
			{
				return;
			}
			nextCleanup = Time.time + 5f;
			List<Transform> list = null;
			foreach (KeyValuePair<Transform, GameObject> label in labels)
			{
				if ((Object)(object)label.Key == (Object)null || (Object)(object)label.Value == (Object)null)
				{
					list = list ?? new List<Transform>();
					list.Add(label.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Transform item in list)
			{
				labels.Remove(item);
			}
			LookWhatIGotPlugin.Dbg($"Cleaned up {list.Count} stale label(s)");
		}

		public static void ShowLabel(Transform anchor, string itemName, int value)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0071: 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_0082: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)anchor == (Object)null))
			{
				HideLabel(anchor);
				GameObject val = new GameObject("LookWhatIGot_Label");
				val.layer = LabelLayer;
				val.transform.SetParent(anchor, false);
				val.transform.localPosition = (DebugPinToCamera ? new Vector3(0f, 0f, 2f) : new Vector3(0f, LabelHeight, 0f));
				val.transform.localRotation = Quaternion.identity;
				Vector3 lossyScale = anchor.lossyScale;
				val.transform.localScale = new Vector3(Mathf.Approximately(lossyScale.x, 0f) ? 1f : (1f / lossyScale.x), Mathf.Approximately(lossyScale.y, 0f) ? 1f : (1f / lossyScale.y), Mathf.Approximately(lossyScale.z, 0f) ? 1f : (1f / lossyScale.z));
				TextMesh val2 = val.AddComponent<TextMesh>();
				val2.text = ((value > 0) ? $"Look what I got\n{itemName}\n${value}" : ("Look what I got\n" + itemName));
				val2.font = labelFont;
				val2.fontSize = 64;
				val2.characterSize = 0.03f;
				val2.anchor = (TextAnchor)4;
				val2.alignment = (TextAlignment)1;
				val2.color = new Color(1f, 0.92f, 0.2f);
				val2.fontStyle = (FontStyle)1;
				MeshRenderer component = val.GetComponent<MeshRenderer>();
				if ((Object)(object)component != (Object)null && (Object)(object)labelFont != (Object)null)
				{
					((Renderer)component).material = labelFont.material;
					((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)component).receiveShadows = false;
				}
				labels[anchor] = val;
				LookWhatIGotPlugin.Dbg($"Label shown -> {itemName} (${value}) parent={((Object)anchor).name}");
			}
		}

		public static void HideLabel(Transform anchor)
		{
			if (!((Object)(object)anchor == (Object)null) && labels.TryGetValue(anchor, out GameObject value))
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
				labels.Remove(anchor);
			}
		}
	}
	public static class LabelNetwork
	{
		private const byte EventCode = 173;

		private static bool subscribed;

		private static string lastSentName;

		private static int lastSentValue = -1;

		private static bool lastSentVisible;

		public static void Initialize()
		{
			if (subscribed)
			{
				return;
			}
			try
			{
				PhotonNetwork.NetworkingClient.EventReceived += OnEvent;
				subscribed = true;
				LookWhatIGotPlugin.Dbg($"Photon event handler registered (code {(byte)173})");
			}
			catch (Exception ex)
			{
				LookWhatIGotPlugin.Log.LogError((object)("Could not register Photon handler: " + ex.Message));
			}
		}

		public static void BroadcastShow(string itemName, int value)
		{
			if (!lastSentVisible || !(lastSentName == itemName) || lastSentValue != value)
			{
				lastSentVisible = true;
				lastSentName = itemName;
				lastSentValue = value;
				Send(visible: true, itemName, value);
			}
		}

		public static void BroadcastHide()
		{
			if (lastSentVisible)
			{
				lastSentVisible = false;
				lastSentName = null;
				lastSentValue = -1;
				Send(visible: false, string.Empty, 0);
			}
		}

		private static void Send(bool visible, string itemName, int value)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0057: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom)
			{
				return;
			}
			try
			{
				object[] array = new object[4]
				{
					PhotonNetwork.LocalPlayer.ActorNumber,
					visible,
					itemName,
					value
				};
				RaiseEventOptions val = new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)0
				};
				PhotonNetwork.RaiseEvent((byte)173, (object)array, val, SendOptions.SendReliable);
			}
			catch (Exception ex)
			{
				LookWhatIGotPlugin.Log.LogError((object)("RaiseEvent failed: " + ex.Message));
			}
		}

		private static void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code != 173)
			{
				return;
			}
			try
			{
				if (!(photonEvent.CustomData is object[] array) || array.Length < 4)
				{
					LookWhatIGotPlugin.Log.LogWarning((object)"Malformed label event ignored.");
					return;
				}
				int num = (int)array[0];
				bool flag = (bool)array[1];
				string itemName = (string)array[2];
				int value = (int)array[3];
				if (num != PhotonNetwork.LocalPlayer.ActorNumber)
				{
					PlayerAvatar val = FindAvatarByActor(num);
					if ((Object)(object)val == (Object)null)
					{
						LookWhatIGotPlugin.Log.LogWarning((object)$"No PlayerAvatar found for actor {num}");
					}
					else if (flag)
					{
						HoldingLabelManager.ShowLabel(((Component)val).transform, itemName, value);
					}
					else
					{
						HoldingLabelManager.HideLabel(((Component)val).transform);
					}
				}
			}
			catch (Exception arg)
			{
				LookWhatIGotPlugin.Log.LogError((object)$"Event handling failed: {arg}");
			}
		}

		private static PlayerAvatar FindAvatarByActor(int actorNumber)
		{
			PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>();
			PlayerAvatar[] array2 = array;
			foreach (PlayerAvatar val in array2)
			{
				PhotonView val2 = ((Component)val).GetComponent<PhotonView>() ?? ((Component)val).GetComponentInParent<PhotonView>() ?? ((Component)val).GetComponentInChildren<PhotonView>();
				if ((Object)(object)val2 != (Object)null && val2.Owner != null && val2.Owner.ActorNumber == actorNumber)
				{
					return val;
				}
			}
			return null;
		}
	}
	[BepInPlugin("com.odinplus.lookwhatigot", "Look What I Got", "1.0.0")]
	public class LookWhatIGotPlugin : BaseUnityPlugin
	{
		private const string MyGuid = "com.odinplus.lookwhatigot";

		private const string PluginName = "Look What I Got";

		private const string VersionString = "1.0.0";

		private const string BuildTag = "complete. Structural integrity questionable. Confidence level: 0%.";

		internal static ManualLogSource Log;

		private readonly Harmony harmony = new Harmony("com.odinplus.lookwhatigot");

		internal static ConfigEntry<bool> CfgOnlyShowValuables;

		internal static ConfigEntry<float> CfgLabelHeight;

		internal static ConfigEntry<int> CfgLabelLayer;

		internal static ConfigEntry<bool> CfgVerbose;

		internal static ConfigEntry<bool> CfgDebugPinToCamera;

		internal static bool Verbose => CfgVerbose?.Value ?? false;

		private void BindConfig()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			CfgOnlyShowValuables = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Only Show Valuables", true, "Ignore doors, hinges, carts and other non-treasure. Turn off if you want every single grab announced.");
			CfgLabelHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Label Height", 2.3f, new ConfigDescription("How far above the player the text floats.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>()));
			CfgLabelLayer = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "Label Layer", 0, new ConfigDescription("Render layer for the text. Only worth touching if labels vanish behind geometry.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 31), Array.Empty<object>()));
			CfgVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Verbose Logging", false, "Full diagnostic output in the BepInEx console. Leave off unless something's broken.");
			CfgDebugPinToCamera = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug Pin To Camera", false, "Pins the label in front of your own eyes instead of on your avatar. Testing aid only.");
		}

		internal static void Dbg(string message)
		{
			if (Verbose && Log != null)
			{
				Log.LogInfo((object)message);
			}
		}

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			Log.LogInfo((object)"Look What I Got v1.0.0 loaded! (build complete. Structural integrity questionable. Confidence level: 0%.)");
			HoldingLabelManager.Initialize();
			LabelNetwork.Initialize();
			GrabPatches.ApplyPatches(harmony);
		}
	}
}
namespace LookWhatIGot.Patches
{
	public static class GrabPatches
	{
		private const BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		public static void ApplyPatches(Harmony harmony)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			MethodInfo methodInfo = null;
			string[] array = new string[3] { "Update", "LateUpdate", "FixedUpdate" };
			foreach (string text in array)
			{
				methodInfo = AccessTools.Method(typeof(PhysGrabber), text, (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					LookWhatIGotPlugin.Dbg("Patching PhysGrabber." + text);
					break;
				}
			}
			if (methodInfo == null)
			{
				LookWhatIGotPlugin.Log.LogError((object)"PhysGrabber has no Update/LateUpdate/FixedUpdate to patch!");
				DumpMethods(typeof(PhysGrabber));
				return;
			}
			try
			{
				MethodInfo methodInfo2 = AccessTools.Method(typeof(GrabPatches), "TickPostfix", (Type[])null, (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				LookWhatIGotPlugin.Dbg("Patch applied successfully.");
			}
			catch (Exception arg)
			{
				LookWhatIGotPlugin.Log.LogError((object)$"Patch failed: {arg}");
			}
		}

		private static void TickPostfix(PhysGrabber __instance)
		{
			try
			{
				if (!((Object)(object)__instance != (Object)(object)PhysGrabber.instance))
				{
					HoldingLabelManager.Tick(__instance);
				}
			}
			catch (Exception arg)
			{
				LookWhatIGotPlugin.Log.LogError((object)$"Tick threw: {arg}");
			}
		}

		private static void DumpMethods(Type t)
		{
			StringBuilder stringBuilder = new StringBuilder("--- methods on " + t.Name + " ---\n");
			MethodInfo[] methods = t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				stringBuilder.AppendLine($"  {methodInfo.ReturnType.Name} {methodInfo.Name}({methodInfo.GetParameters().Length} args)");
			}
			LookWhatIGotPlugin.Log.LogInfo((object)stringBuilder.ToString());
		}
	}
}