Decompiled source of Noxys Dynamic Radial Menu v1.0.6

NoxyRadialMenu.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModdingUtils.Utils;
using NoxyRadialMenu.UI;
using UnityEngine;
using UnityEngine.UI;

[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: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.0")]
[module: UnverifiableCode]
[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 NoxyRadialMenu
{
	[BepInPlugin("com.noxy.rounds.radialmenu", "Noxy Radial Menu", "1.0.6")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class RadialMenuPlugin : BaseUnityPlugin
	{
		private const string ModId = "com.noxy.rounds.radialmenu";

		private const string ModName = "Noxy Radial Menu";

		public const string Version = "1.0.6";

		public static RadialMenuPlugin instance;

		private void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			instance = this;
			new Harmony("com.noxy.rounds.radialmenu").PatchAll();
			GameObject val = new GameObject("NoxyRadialMenuManager");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<RadialMenuManager>();
		}
	}
}
namespace NoxyRadialMenu.UI
{
	public class RadialMenuManager : MonoBehaviour
	{
		private const int PageSize = 8;

		private GameObject canvasObj;

		private GameObject menuContainer;

		private Text statusText;

		private Sprite cachedCircleSprite;

		private readonly List<GameObject> slices = new List<GameObject>();

		private readonly List<Image> sliceImages = new List<Image>();

		private readonly List<int> selectedIndices = new List<int>();

		private readonly Dictionary<string, CardInfo> cardMapping = new Dictionary<string, CardInfo>(StringComparer.Ordinal);

		private List<string> currentOptions = new List<string>();

		private int hoveredIndex = -1;

		private int maxSelections = 1;

		private int page;

		private Coroutine activeCoroutine;

		public bool isOpen;

		public bool isApplyingCards;

		public static bool IsMenuEnabled;

		public static RadialMenuManager Instance { get; private set; }

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0079: 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_00b0: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			canvasObj = new GameObject("NoxyRadialMenuCanvas", new Type[1] { typeof(RectTransform) });
			canvasObj.transform.SetParent(((Component)this).transform, false);
			Canvas obj = canvasObj.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 1000;
			CanvasScaler obj2 = canvasObj.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			menuContainer = new GameObject("MenuContainer", new Type[1] { typeof(RectTransform) });
			menuContainer.transform.SetParent(canvasObj.transform, false);
			RectTransform val = (RectTransform)menuContainer.transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.sizeDelta = new Vector2(800f, 800f);
			statusText = CreateText(menuContainer.transform, "Status", new Vector2(0f, -365f), new Vector2(760f, 80f), 18);
			menuContainer.SetActive(false);
		}

		private static Text CreateText(Transform parent, string name, Vector2 position, Vector2 size, int fontSize)
		{
			//IL_0014: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0038: 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)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchoredPosition = position;
			val2.sizeDelta = size;
			Text obj = val.AddComponent<Text>();
			obj.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			obj.alignment = (TextAnchor)4;
			obj.fontSize = fontSize;
			((Graphic)obj).color = Color.white;
			((Graphic)obj).raycastTarget = false;
			obj.supportRichText = false;
			obj.resizeTextForBestFit = true;
			obj.resizeTextMinSize = 12;
			obj.resizeTextMaxSize = fontSize;
			return obj;
		}

		private static Type JjkCardType(CardInfo card)
		{
			if (!((Object)(object)card == (Object)null))
			{
				return (from c in ((Component)card).GetComponents<Component>()
					where (Object)(object)c != (Object)null
					select ((object)c).GetType()).FirstOrDefault((Type t) => t.Assembly.GetName().Name == "JJKCardsMod" && t.Namespace == "JJKCardsMod.Cards" && t.Name.EndsWith("Card", StringComparison.Ordinal));
			}
			return null;
		}

		private static string CardId(CardInfo card)
		{
			object obj = JjkCardType(card)?.FullName;
			if (obj == null)
			{
				if (!((Object)(object)card == (Object)null))
				{
					return ((Object)((Component)card).gameObject).name.Replace("(Clone)", "").Trim();
				}
				obj = "";
			}
			return (string)obj;
		}

		private static bool IsTechnique(CardInfo card)
		{
			Type type = JjkCardType(card);
			if (type == null)
			{
				return false;
			}
			Type type2 = type;
			while (type2 != null)
			{
				if (type2.FullName == "JJKCardsMod.Cards.BaseCharacterCard")
				{
					return false;
				}
				type2 = type2.BaseType;
			}
			return true;
		}

		private void BuildCardMapping()
		{
			cardMapping.Clear();
			IOrderedEnumerable<CardInfo> orderedEnumerable = (from c in Resources.FindObjectsOfTypeAll<CardInfo>()
				where (Object)(object)c != (Object)null
				orderby ((Object)((Component)c).gameObject).name.EndsWith("(Clone)", StringComparison.Ordinal)
				select c).ThenBy<CardInfo, string>(CardId, StringComparer.Ordinal);
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (CardInfo item in orderedEnumerable)
			{
				string text = CardId(item);
				if (IsTechnique(item) && hashSet.Add(text))
				{
					string text2 = (string.IsNullOrWhiteSpace(item.cardName) ? text : item.cardName);
					string text3 = text2;
					if (cardMapping.ContainsKey(text3))
					{
						text3 = text2 + " [" + text + "]";
					}
					while (cardMapping.ContainsKey(text3))
					{
						text3 += "*";
					}
					cardMapping.Add(text3, item);
				}
			}
		}

		private void Update()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if (isOpen && (!IsMenuEnabled || Input.GetKeyDown((KeyCode)27)))
			{
				CancelMenu();
				return;
			}
			if (Input.GetKeyDown((KeyCode)118) && !isOpen && !isApplyingCards && IsMenuEnabled)
			{
				BuildCardMapping();
				OpenMenu(cardMapping.Keys.OrderBy<string, string>((string k) => k, StringComparer.Ordinal).ToList(), 2);
			}
			if (isOpen)
			{
				float y = Input.mouseScrollDelta.y;
				if (y != 0f)
				{
					ChangePage((!(y > 0f)) ? 1 : (-1));
				}
				HandleMouseSelection();
				if (Input.GetMouseButtonDown(0) && hoveredIndex >= 0)
				{
					ToggleSelection(hoveredIndex);
				}
				if (Input.GetKeyUp((KeyCode)118))
				{
					CloseMenu();
				}
			}
		}

		public void OpenMenu(List<string> options, int maxAllowed = 1)
		{
			if (!isApplyingCards)
			{
				CancelMenu();
				if (options != null && options.Count != 0)
				{
					currentOptions = new List<string>(options);
					maxSelections = Math.Max(1, Math.Min(maxAllowed, options.Count));
					page = 0;
					isOpen = true;
					menuContainer.SetActive(true);
					CreatePizzaSlices();
				}
			}
		}

		public void CancelMenu()
		{
			isOpen = false;
			hoveredIndex = -1;
			selectedIndices.Clear();
			if ((Object)(object)menuContainer != (Object)null)
			{
				menuContainer.SetActive(false);
			}
		}

		public List<int> CloseMenu()
		{
			List<int> list = new List<int>();
			if (!isOpen || isApplyingCards)
			{
				return list;
			}
			if (hoveredIndex >= 0 && hoveredIndex < currentOptions.Count)
			{
				list.AddRange(selectedIndices);
				if (list.Count == 0)
				{
					list.Add(hoveredIndex);
				}
			}
			CancelMenu();
			if (list.Count != 0)
			{
				isApplyingCards = true;
				activeCoroutine = ((MonoBehaviour)this).StartCoroutine(ApplySafely(list));
			}
			return list;
		}

		private void ChangePage(int direction)
		{
			int num = (currentOptions.Count + 8 - 1) / 8;
			if (num > 1)
			{
				page = ((page + direction) % num + num) % num;
				hoveredIndex = -1;
				CreatePizzaSlices();
			}
		}

		private void CreatePizzaSlices()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00ca: 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_00da: 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_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: 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_01d5: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject slice in slices)
			{
				slice.SetActive(false);
				Object.Destroy((Object)(object)slice);
			}
			slices.Clear();
			sliceImages.Clear();
			int num = Math.Min(8, currentOptions.Count - page * 8);
			if (num > 0)
			{
				float num2 = 360f / (float)num;
				for (int i = 0; i < num; i++)
				{
					GameObject val = new GameObject("Slice_" + i, new Type[1] { typeof(RectTransform) });
					val.transform.SetParent(menuContainer.transform, false);
					RectTransform val2 = (RectTransform)val.transform;
					val2.sizeDelta = new Vector2(600f, 600f);
					((Transform)val2).localRotation = Quaternion.Euler(0f, 0f, (float)(-i) * num2 + num2 / 2f);
					Image val3 = val.AddComponent<Image>();
					val3.sprite = CircleSprite();
					val3.type = (Type)3;
					val3.fillMethod = (FillMethod)4;
					val3.fillOrigin = 2;
					val3.fillClockwise = true;
					val3.fillAmount = 1f / (float)num;
					((Graphic)val3).raycastTarget = false;
					float num3 = (float)i * num2 * ((float)Math.PI / 180f);
					Text obj = CreateText(val.transform, "Title", Vector2.zero, new Vector2(130f, 58f), 18);
					((Transform)((Graphic)obj).rectTransform).position = menuContainer.transform.TransformPoint(new Vector3(Mathf.Sin(num3) * 210f, Mathf.Cos(num3) * 210f, 0f));
					((Transform)((Graphic)obj).rectTransform).rotation = menuContainer.transform.rotation;
					obj.text = currentOptions[page * 8 + i];
					slices.Add(val);
					sliceImages.Add(val3);
				}
				UpdateHighlights();
			}
		}

		private void HandleMouseSelection()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Vector2 hover = default(Vector2);
			if (RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)menuContainer.transform, Vector2.op_Implicit(Input.mousePosition), (Camera)null, ref hover))
			{
				SetHover(hover);
			}
		}

		private void SetHover(Vector2 local)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			hoveredIndex = -1;
			if (slices.Count != 0 && ((Vector2)(ref local)).magnitude >= 50f)
			{
				float num = 360f / (float)slices.Count;
				float num2 = (Mathf.Atan2(local.x, local.y) * 57.29578f + 360f + num / 2f) % 360f;
				hoveredIndex = page * 8 + Math.Min(slices.Count - 1, Mathf.FloorToInt(num2 / num));
			}
			UpdateHighlights();
		}

		private void ToggleSelection(int index)
		{
			if (index < 0 || index >= currentOptions.Count)
			{
				return;
			}
			if (!selectedIndices.Remove(index))
			{
				if (selectedIndices.Count >= maxSelections)
				{
					selectedIndices.RemoveAt(0);
				}
				selectedIndices.Add(index);
			}
			UpdateHighlights();
		}

		private void UpdateHighlights()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < sliceImages.Count; i++)
			{
				int num = page * 8 + i;
				((Graphic)sliceImages[i]).color = (selectedIndices.Contains(num) ? new Color(0.6f, 0f, 1f, 0.95f) : ((num == hoveredIndex) ? new Color(0.4f, 0f, 0.6f, 0.95f) : new Color(0.1f, 0.1f, 0.1f, 0.9f)));
			}
			if ((Object)(object)statusText != (Object)null)
			{
				statusText.text = $"{page + 1}/{Math.Max(1, (currentOptions.Count + 8 - 1) / 8)}  |  Selected {selectedIndices.Count}/{maxSelections}\nScroll: page   Click: select   Release V: apply   Center / Esc: cancel";
			}
		}

		private Player GetLocalPlayer()
		{
			if ((Object)(object)PlayerManager.instance == (Object)null || PlayerManager.instance.players == null)
			{
				return null;
			}
			return ((IEnumerable<Player>)PlayerManager.instance.players).FirstOrDefault((Func<Player, bool>)((Player p) => (Object)(object)p != (Object)null && (Object)(object)p.data != (Object)null && (Object)(object)p.data.view != (Object)null && p.data.view.IsMine));
		}

		private static List<CardInfo> CardsToPurge(IEnumerable<CardInfo> deck, IEnumerable<CardInfo> desired)
		{
			HashSet<string> ids = new HashSet<string>(desired.Select(CardId), StringComparer.Ordinal);
			return deck.Where((CardInfo c) => IsTechnique(c) && !ids.Contains(CardId(c))).ToList();
		}

		private IEnumerator ApplySafely(List<int> selection)
		{
			IEnumerator operation = ApplyCardsCoroutine(selection);
			try
			{
				while (true)
				{
					object current;
					try
					{
						if (!operation.MoveNext())
						{
							break;
						}
						current = operation.Current;
					}
					catch (Exception ex)
					{
						Debug.LogError("[NoxyRadialMenu] Card swap failed: " + ex);
						break;
					}
					yield return current;
				}
			}
			finally
			{
				RadialMenuManager radialMenuManager = this;
				(operation as IDisposable)?.Dispose();
				radialMenuManager.isApplyingCards = false;
				radialMenuManager.activeCoroutine = null;
			}
		}

		private IEnumerator ApplyCardsCoroutine(List<int> selection)
		{
			Player player = GetLocalPlayer();
			if ((Object)(object)player == (Object)null || player.data.currentCards == null || Cards.instance == null)
			{
				yield break;
			}
			List<CardInfo> desired = new List<CardInfo>();
			foreach (int item in selection)
			{
				if (item >= 0 && item < currentOptions.Count && cardMapping.TryGetValue(currentOptions[item], out var value) && !((Object)(object)value == (Object)null))
				{
					if (!desired.Contains(value))
					{
						desired.Add(value);
					}
					continue;
				}
				yield break;
			}
			if (desired.Count == 0)
			{
				yield break;
			}
			List<CardInfo> list = CardsToPurge(player.data.currentCards, desired);
			Component component = ((Component)player).GetComponent("YutaCopyBehaviour");
			FieldInfo fieldInfo = (((Object)(object)component == (Object)null) ? null : ((object)component).GetType().GetField("copiedCardInfo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
			object? obj = fieldInfo?.GetValue(component);
			CardInfo val = (CardInfo)((obj is CardInfo) ? obj : null);
			HashSet<int> hashSet = new HashSet<int>();
			if (list.Any((CardInfo c) => JjkCardType(c)?.Name == "YutaCopyCard") && (Object)(object)val != (Object)null)
			{
				int num = player.data.currentCards.LastIndexOf(val);
				if (num >= 0)
				{
					hashSet.Add(num);
				}
				fieldInfo.SetValue(component, null);
			}
			for (int num2 = 0; num2 < player.data.currentCards.Count; num2++)
			{
				CardInfo val2 = player.data.currentCards[num2];
				if ((Object)(object)val2 != (Object)null && list.Contains(val2))
				{
					hashSet.Add(num2);
				}
			}
			if (hashSet.Count > 0)
			{
				Cards.instance.RemoveCardsFromPlayer(player, hashSet.ToArray());
				yield return (object)new WaitForSecondsRealtime(0.6f);
			}
			foreach (CardInfo card in desired)
			{
				if (!((Object)(object)player == (Object)null) && !((Object)(object)player.data == (Object)null))
				{
					if (!player.data.currentCards.Any((CardInfo c) => CardId(c) == CardId(card)))
					{
						Cards.instance.AddCardToPlayer(player, card, false, "", 0f, 0f, true);
						yield return null;
					}
					continue;
				}
				yield break;
			}
		}

		private Sprite CircleSprite()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cachedCircleSprite != (Object)null)
			{
				return cachedCircleSprite;
			}
			Texture2D val = new Texture2D(512, 512, (TextureFormat)4, false);
			Color32[] array = (Color32[])(object)new Color32[262144];
			for (int i = 0; i < 512; i++)
			{
				for (int j = 0; j < 512; j++)
				{
					array[i * 512 + j] = (((j - 256) * (j - 256) + (i - 256) * (i - 256) <= 65536) ? new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue) : new Color32((byte)0, (byte)0, (byte)0, (byte)0));
				}
			}
			val.SetPixels32(array);
			val.Apply(false, true);
			cachedCircleSprite = Sprite.Create(val, new Rect(0f, 0f, 512f, 512f), new Vector2(0.5f, 0.5f));
			return cachedCircleSprite;
		}

		private void OnDisable()
		{
			CancelMenu();
			if (activeCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(activeCoroutine);
			}
			activeCoroutine = null;
			isApplyingCards = false;
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			if ((Object)(object)cachedCircleSprite != (Object)null)
			{
				Object.Destroy((Object)(object)cachedCircleSprite.texture);
				Object.Destroy((Object)(object)cachedCircleSprite);
			}
		}
	}
}