Decompiled source of NativeCursor v2.1.0

NativeCursor.dll

Decompiled 5 days ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using TMPro;
using UnboundLib;
using UnboundLib.Utils.UI;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("NativeCursor")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NativeCursor")]
[assembly: AssemblyTitle("NativeCursor")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NativeCursor
{
	[BepInPlugin("oskar.rounds.nativecursor", "NativeCursor", "2.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("Rounds.exe")]
	public class NativeCursorPlugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__16_0;

			internal void <Start>b__16_0()
			{
			}
		}

		public const string ModGuid = "oskar.rounds.nativecursor";

		public const string ModName = "NativeCursor";

		public const string ModVersion = "2.1.0";

		private ConfigEntry<bool> modEnabled;

		private ConfigEntry<string> mode;

		private ConfigEntry<float> recaptureInterval;

		private ConfigEntry<bool> animateFrames;

		private ConfigEntry<string> imagePath;

		private ConfigEntry<int> hotspotX;

		private ConfigEntry<int> hotspotY;

		private Texture2D cursorTex;

		private Vector2 cursorHotspot;

		private string lastError = "";

		private float nextCapture;

		private int animFrame;

		private void Awake()
		{
			modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Applies live from the in-game MODS -> NativeCursor menu.");
			mode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Mode", "CaptureWindows", "CaptureWindows = show your live Windows cursor. ImageFile = use a PNG. GameDefault = let ROUNDS draw its crosshair.");
			recaptureInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RecaptureIntervalSeconds", 0.2f, "CaptureWindows only: how often to re-grab the OS cursor so it follows live changes (e.g. a cursor-effects app). 0 = never (manual recapture only).");
			animateFrames = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnimateFrames", false, "CaptureWindows only: step through animated (.ani) cursor frames on each recapture.");
			imagePath = ((BaseUnityPlugin)this).Config.Bind<string>("ImageFile", "ImagePath", "", "Path to a PNG to use as the cursor. Empty = <config folder>\\nativecursor.png.");
			hotspotX = ((BaseUnityPlugin)this).Config.Bind<int>("ImageFile", "HotspotX", 0, "Click point X (px from image's top-left).");
			hotspotY = ((BaseUnityPlugin)this).Config.Bind<int>("ImageFile", "HotspotY", 0, "Click point Y (px from image's top-left).");
			SceneManager.sceneLoaded += OnSceneLoaded;
			RebuildCursor("Awake");
			ApplyEnabledState();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"NativeCursor 2.1.0 active.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[Diag] Hotkeys: F8 = toggle mod, F9 = dump diagnostics, F10 = recapture cursor.");
		}

		private void Start()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[Diag] Start() reached. Registering MODS menu...");
			try
			{
				object obj = <>c.<>9__16_0;
				if (obj == null)
				{
					UnityAction val = delegate
					{
					};
					<>c.<>9__16_0 = val;
					obj = (object)val;
				}
				Unbound.RegisterMenu("NativeCursor", (UnityAction)obj, (Action<GameObject>)BuildMenu, (GameObject)null, true);
				Unbound.RegisterClientSideMod("oskar.rounds.nativecursor");
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Diag] MODS menu registered.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Diag] RegisterMenu FAILED: " + ex));
			}
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode m)
		{
			ApplyEnabledState();
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)289))
			{
				modEnabled.Value = !modEnabled.Value;
				ApplyEnabledState();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[Diag] F8 -> Enabled = " + modEnabled.Value));
			}
			if (Input.GetKeyDown((KeyCode)290))
			{
				DumpDiag("F9");
			}
			if (Input.GetKeyDown((KeyCode)291))
			{
				RebuildCursor("F10");
			}
		}

		private void LateUpdate()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (modEnabled != null && modEnabled.Value)
			{
				TickRecapture();
				if (!Cursor.visible)
				{
					Cursor.visible = true;
				}
				if ((int)Cursor.lockState != 0)
				{
					Cursor.lockState = (CursorLockMode)0;
				}
				ApplyCursor();
			}
		}

		private void ApplyEnabledState()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (modEnabled != null && modEnabled.Value)
			{
				ApplyCursor();
			}
			else
			{
				Cursor.SetCursor((Texture2D)null, Vector2.zero, (CursorMode)0);
			}
		}

		private void ApplyCursor()
		{
			//IL_0038: 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)
			if (modEnabled != null && modEnabled.Value)
			{
				if ((Object)(object)cursorTex != (Object)null)
				{
					Cursor.SetCursor(cursorTex, cursorHotspot, (CursorMode)0);
				}
				else
				{
					Cursor.SetCursor((Texture2D)null, Vector2.zero, (CursorMode)0);
				}
			}
		}

		private void TickRecapture()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (mode == null || mode.Value != "CaptureWindows")
			{
				return;
			}
			float value = recaptureInterval.Value;
			if (!(value <= 0f) && !(Time.unscaledTime < nextCapture))
			{
				nextCapture = Time.unscaledTime + value;
				int istep = (animateFrames.Value ? animFrame++ : 0);
				if (animFrame > 100000)
				{
					animFrame = 0;
				}
				Vector2 hotspot;
				string error;
				Texture2D val = Win32Cursor.CaptureArrow(istep, out hotspot, out error);
				if ((Object)(object)val != (Object)null)
				{
					SwapCursorTex(val);
					cursorHotspot = hotspot;
				}
				else
				{
					lastError = error;
				}
			}
		}

		private void SwapCursorTex(Texture2D newTex)
		{
			if ((Object)(object)cursorTex != (Object)null && (Object)(object)cursorTex != (Object)(object)newTex)
			{
				Object.Destroy((Object)(object)cursorTex);
			}
			cursorTex = newTex;
		}

		private unsafe void RebuildCursor(string reason)
		{
			//IL_004d: 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_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			lastError = "";
			nextCapture = 0f;
			animFrame = 0;
			string text = ((mode != null) ? mode.Value : "CaptureWindows");
			try
			{
				if (text == "GameDefault")
				{
					SwapCursorTex(null);
					cursorHotspot = Vector2.zero;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[Diag] RebuildCursor(" + reason + "): Mode=GameDefault -> ROUNDS crosshair."));
				}
				else if (text == "ImageFile")
				{
					string text2 = (string.IsNullOrEmpty(imagePath.Value) ? Path.Combine(Paths.ConfigPath, "nativecursor.png") : imagePath.Value);
					if (!File.Exists(text2))
					{
						lastError = "image not found: " + text2;
						SwapCursorTex(null);
						((BaseUnityPlugin)this).Logger.LogWarning((object)("[Diag] RebuildCursor: " + lastError));
					}
					else
					{
						Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
						ImageConversion.LoadImage(val, File.ReadAllBytes(text2));
						val.Apply();
						SwapCursorTex(val);
						cursorHotspot = new Vector2((float)hotspotX.Value, (float)hotspotY.Value);
						ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
						string[] obj = new string[10]
						{
							"[Diag] RebuildCursor(",
							reason,
							"): loaded ",
							text2,
							" (",
							((Texture)val).width.ToString(),
							"x",
							((Texture)val).height.ToString(),
							"), hotspot ",
							null
						};
						Vector2 val2 = cursorHotspot;
						obj[9] = ((object)(*(Vector2*)(&val2))/*cast due to .constrained prefix*/).ToString();
						logger.LogInfo((object)string.Concat(obj));
					}
				}
				else
				{
					Vector2 hotspot;
					Texture2D val3 = Win32Cursor.CaptureArrow(0, out hotspot, out lastError);
					SwapCursorTex(val3);
					cursorHotspot = hotspot;
					if ((Object)(object)val3 != (Object)null)
					{
						ManualLogSource logger2 = ((BaseUnityPlugin)this).Logger;
						string[] obj2 = new string[8]
						{
							"[Diag] RebuildCursor(",
							reason,
							"): captured ",
							((Texture)val3).width.ToString(),
							"x",
							((Texture)val3).height.ToString(),
							", hotspot ",
							null
						};
						Vector2 val2 = hotspot;
						obj2[7] = ((object)(*(Vector2*)(&val2))/*cast due to .constrained prefix*/).ToString();
						logger2.LogInfo((object)string.Concat(obj2));
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("[Diag] RebuildCursor(" + reason + "): capture failed: " + lastError));
					}
				}
			}
			catch (Exception ex)
			{
				lastError = ex.Message;
				SwapCursorTex(null);
				((BaseUnityPlugin)this).Logger.LogError((object)("[Diag] RebuildCursor threw: " + ex));
			}
			ApplyEnabledState();
		}

		private void BuildMenu(GameObject menu)
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Expected O, but got Unknown
			try
			{
				TextMeshProUGUI val = default(TextMeshProUGUI);
				MenuHandler.CreateText("NativeCursor", menu, ref val, 60, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateText(" ", menu, ref val, 30, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateToggle(modEnabled.Value, "Enabled", menu, (UnityAction<bool>)delegate(bool on)
				{
					modEnabled.Value = on;
					ApplyEnabledState();
				}, 60, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateToggle(recaptureInterval.Value > 0f, "Live update (follow OS cursor)", menu, (UnityAction<bool>)delegate(bool on)
				{
					recaptureInterval.Value = (on ? 0.2f : 0f);
					nextCapture = 0f;
				}, 55, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateText(" ", menu, ref val, 30, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateText("Cursor source:", menu, ref val, 45, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateButton("Use my Windows cursor", menu, (UnityAction)delegate
				{
					mode.Value = "CaptureWindows";
					RebuildCursor("menu");
				}, 45, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateButton("Use PNG file", menu, (UnityAction)delegate
				{
					mode.Value = "ImageFile";
					RebuildCursor("menu");
				}, 45, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateButton("Game default (crosshair)", menu, (UnityAction)delegate
				{
					mode.Value = "GameDefault";
					RebuildCursor("menu");
				}, 45, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateText(" ", menu, ref val, 30, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateButton("Recapture / reload cursor", menu, (UnityAction)delegate
				{
					RebuildCursor("menu-recapture");
				}, 45, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateButton("Dump diagnostics to log", menu, (UnityAction)delegate
				{
					DumpDiag("menu");
				}, 45, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateText(" ", menu, ref val, 30, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
				MenuHandler.CreateText("Live update re-grabs the OS cursor ~5x/sec. PNG mode reads <config>\\nativecursor.png (set the click point with HotspotX/Y in the config file).", menu, ref val, 28, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Diag] BuildMenu threw: " + ex));
			}
		}

		private unsafe void DumpDiag(string reason)
		{
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
				string[] obj = new string[25]
				{
					"[Diag] ==== NativeCursor (",
					reason,
					") ====\n[Diag] enabled=",
					(modEnabled != null && modEnabled.Value).ToString(),
					" mode=",
					(mode != null) ? mode.Value : "?",
					" recaptureInterval=",
					((recaptureInterval != null) ? recaptureInterval.Value : (-1f)).ToString(),
					" haveTexture=",
					((Object)(object)cursorTex != (Object)null).ToString(),
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null
				};
				object obj2;
				if (!((Object)(object)cursorTex != (Object)null))
				{
					obj2 = "";
				}
				else
				{
					string[] obj3 = new string[7]
					{
						" (",
						((Texture)cursorTex).width.ToString(),
						"x",
						((Texture)cursorTex).height.ToString(),
						" hotspot ",
						null,
						null
					};
					Vector2 val = cursorHotspot;
					obj3[5] = ((object)(*(Vector2*)(&val))/*cast due to .constrained prefix*/).ToString();
					obj3[6] = ")";
					obj2 = string.Concat(obj3);
				}
				obj[10] = (string)obj2;
				obj[11] = " lastError='";
				obj[12] = lastError;
				obj[13] = "'\n[Diag] Screen ";
				obj[14] = Screen.width.ToString();
				obj[15] = "x";
				obj[16] = Screen.height.ToString();
				obj[17] = " mode=";
				obj[18] = ((object)Screen.fullScreenMode/*cast due to .constrained prefix*/).ToString();
				obj[19] = " focused=";
				obj[20] = Application.isFocused.ToString();
				obj[21] = "\n[Diag] Cursor.visible=";
				obj[22] = Cursor.visible.ToString();
				obj[23] = " lockState=";
				obj[24] = ((object)Cursor.lockState/*cast due to .constrained prefix*/).ToString();
				logger.LogInfo((object)string.Concat(obj));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Diag] DumpDiag failed: " + ex));
			}
		}
	}
	internal static class Win32Cursor
	{
		private struct ICONINFO
		{
			public bool fIcon;

			public int xHotspot;

			public int yHotspot;

			public IntPtr hbmMask;

			public IntPtr hbmColor;
		}

		private struct BITMAP
		{
			public int bmType;

			public int bmWidth;

			public int bmHeight;

			public int bmWidthBytes;

			public ushort bmPlanes;

			public ushort bmBitsPixel;

			public IntPtr bmBits;
		}

		private struct BITMAPINFOHEADER
		{
			public uint biSize;

			public int biWidth;

			public int biHeight;

			public ushort biPlanes;

			public ushort biBitCount;

			public uint biCompression;

			public uint biSizeImage;

			public int biXPelsPerMeter;

			public int biYPelsPerMeter;

			public uint biClrUsed;

			public uint biClrImportant;
		}

		private const int IDC_ARROW = 32512;

		private const int DI_NORMAL = 3;

		[DllImport("user32.dll")]
		private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);

		[DllImport("user32.dll")]
		private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);

		[DllImport("user32.dll")]
		private static extern bool DrawIconEx(IntPtr hdc, int x, int y, IntPtr hIcon, int cx, int cy, int istep, IntPtr hbr, int flags);

		[DllImport("user32.dll")]
		private static extern IntPtr GetDC(IntPtr hWnd);

		[DllImport("user32.dll")]
		private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

		[DllImport("gdi32.dll")]
		private static extern IntPtr CreateCompatibleDC(IntPtr hdc);

		[DllImport("gdi32.dll")]
		private static extern bool DeleteDC(IntPtr hdc);

		[DllImport("gdi32.dll")]
		private static extern IntPtr SelectObject(IntPtr hdc, IntPtr h);

		[DllImport("gdi32.dll")]
		private static extern bool DeleteObject(IntPtr h);

		[DllImport("gdi32.dll")]
		private static extern int GetObject(IntPtr h, int cb, ref BITMAP lp);

		[DllImport("gdi32.dll")]
		private static extern IntPtr CreateDIBSection(IntPtr hdc, ref BITMAPINFOHEADER pbmi, uint usage, out IntPtr bits, IntPtr hSection, uint offset);

		public static Texture2D CaptureArrow(int istep, out Vector2 hotspot, out string error)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_039b: 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_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Expected O, but got Unknown
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			hotspot = Vector2.zero;
			error = "";
			IntPtr intPtr = IntPtr.Zero;
			IntPtr intPtr2 = IntPtr.Zero;
			IntPtr intPtr3 = IntPtr.Zero;
			IntPtr intPtr4 = IntPtr.Zero;
			try
			{
				IntPtr intPtr5 = LoadCursor(IntPtr.Zero, 32512);
				if (intPtr5 == IntPtr.Zero)
				{
					error = "LoadCursor returned null";
					return null;
				}
				if (!GetIconInfo(intPtr5, out var piconinfo))
				{
					error = "GetIconInfo failed";
					return null;
				}
				hotspot = new Vector2((float)piconinfo.xHotspot, (float)piconinfo.yHotspot);
				BITMAP lp = default(BITMAP);
				int bmWidth;
				int num;
				if (piconinfo.hbmColor != IntPtr.Zero)
				{
					GetObject(piconinfo.hbmColor, Marshal.SizeOf(typeof(BITMAP)), ref lp);
					bmWidth = lp.bmWidth;
					num = lp.bmHeight;
				}
				else
				{
					GetObject(piconinfo.hbmMask, Marshal.SizeOf(typeof(BITMAP)), ref lp);
					bmWidth = lp.bmWidth;
					num = lp.bmHeight / 2;
				}
				if (piconinfo.hbmColor != IntPtr.Zero)
				{
					DeleteObject(piconinfo.hbmColor);
				}
				if (piconinfo.hbmMask != IntPtr.Zero)
				{
					DeleteObject(piconinfo.hbmMask);
				}
				if (bmWidth <= 0 || num <= 0)
				{
					error = "bad cursor size " + bmWidth + "x" + num;
					return null;
				}
				bmWidth = Mathf.Clamp(bmWidth, 1, 256);
				num = Mathf.Clamp(num, 1, 256);
				BITMAPINFOHEADER pbmi = new BITMAPINFOHEADER
				{
					biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)),
					biWidth = bmWidth,
					biHeight = -num,
					biPlanes = 1,
					biBitCount = 32,
					biCompression = 0u
				};
				intPtr4 = GetDC(IntPtr.Zero);
				intPtr = CreateCompatibleDC(intPtr4);
				intPtr2 = CreateDIBSection(intPtr, ref pbmi, 0u, out var bits, IntPtr.Zero, 0u);
				if (intPtr2 == IntPtr.Zero || bits == IntPtr.Zero)
				{
					error = "CreateDIBSection failed";
					return null;
				}
				intPtr3 = SelectObject(intPtr, intPtr2);
				int count = bmWidth * num * 4;
				byte[] array = DrawOver(intPtr, bits, count, 0, intPtr5, bmWidth, num, istep);
				byte[] array2 = DrawOver(intPtr, bits, count, byte.MaxValue, intPtr5, bmWidth, num, istep);
				Color32[] array3 = (Color32[])(object)new Color32[bmWidth * num];
				Color32 val = default(Color32);
				for (int i = 0; i < num; i++)
				{
					for (int j = 0; j < bmWidth; j++)
					{
						int num2 = (i * bmWidth + j) * 4;
						int num3 = array[num2];
						int num4 = array[num2 + 1];
						int num5 = array[num2 + 2];
						int num6 = array2[num2];
						int num7 = array2[num2 + 1];
						int num8 = (array2[num2 + 2] - num5 + (num7 - num4) + (num6 - num3)) / 3;
						int num9 = Mathf.Clamp(255 - num8, 0, 255);
						if (num9 <= 0)
						{
							((Color32)(ref val))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
						}
						else
						{
							int num10 = Mathf.Clamp(num5 * 255 / num9, 0, 255);
							int num11 = Mathf.Clamp(num4 * 255 / num9, 0, 255);
							int num12 = Mathf.Clamp(num3 * 255 / num9, 0, 255);
							((Color32)(ref val))..ctor((byte)num10, (byte)num11, (byte)num12, (byte)num9);
						}
						array3[(num - 1 - i) * bmWidth + j] = val;
					}
				}
				Texture2D val2 = new Texture2D(bmWidth, num, (TextureFormat)4, false);
				val2.SetPixels32(array3);
				val2.Apply();
				return val2;
			}
			catch (Exception ex)
			{
				error = ex.Message;
				return null;
			}
			finally
			{
				if (intPtr != IntPtr.Zero && intPtr3 != IntPtr.Zero)
				{
					SelectObject(intPtr, intPtr3);
				}
				if (intPtr2 != IntPtr.Zero)
				{
					DeleteObject(intPtr2);
				}
				if (intPtr != IntPtr.Zero)
				{
					DeleteDC(intPtr);
				}
				if (intPtr4 != IntPtr.Zero)
				{
					ReleaseDC(IntPtr.Zero, intPtr4);
				}
			}
		}

		private static byte[] DrawOver(IntPtr memDC, IntPtr bits, int count, byte fill, IntPtr hCur, int w, int h, int istep)
		{
			byte[] array = new byte[count];
			for (int i = 0; i < count; i++)
			{
				array[i] = fill;
			}
			Marshal.Copy(array, 0, bits, count);
			DrawIconEx(memDC, 0, 0, hCur, w, h, istep, IntPtr.Zero, 3);
			Marshal.Copy(bits, array, 0, count);
			return array;
		}
	}
}