Decompiled source of CardDeletion v1.0.0

plugins/CardDeletion/CardDeletion.dll

Decompiled 3 days 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 BepInEx.Logging;
using HarmonyLib;
using ModdingUtils.Utils;
using UnboundLib;
using UnboundLib.GameModes;
using UnboundLib.Networking;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: AssemblyCompany("Rounds2Mod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Rounds2Mod")]
[assembly: AssemblyTitle("Rounds2Mod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Rounds2Mod;

internal static class CardDeleteLog
{
	private const string Sep = "=====================";

	public static void Section(string title)
	{
		Plugin.Logger.LogInfo((object)"=====================");
		Plugin.Logger.LogInfo((object)("[Rounds2Mod] " + title));
		Plugin.Logger.LogInfo((object)"=====================");
	}

	public static void Line(string message)
	{
		Plugin.Logger.LogInfo((object)("[Rounds2Mod] " + message));
	}

	public static void Warn(string message)
	{
		Plugin.Logger.LogWarning((object)("[Rounds2Mod] " + message));
	}

	public static void Error(string message)
	{
		Plugin.Logger.LogError((object)("[Rounds2Mod] " + message));
	}
}
public class CardBarDeleteButton : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, IPointerEnterHandler, IPointerExitHandler
{
	private static readonly FieldInfo s_cardField = AccessTools.Field(typeof(CardBarButton), "card");

	private Image _icon;

	private Color _originalColor;

	private void Awake()
	{
		//IL_0021: 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)
		_icon = ((Component)this).GetComponentInChildren<Image>();
		if ((Object)(object)_icon != (Object)null)
		{
			_originalColor = ((Graphic)_icon).color;
		}
	}

	public void OnPointerEnter(PointerEventData eventData)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		if (CardDeleteManager.isPickPhase && CardDeleteManager.IsLocalPlayerTurn())
		{
			if ((Object)(object)_icon != (Object)null)
			{
				((Graphic)_icon).color = new Color(1f, 0.28f, 0.28f, _originalColor.a);
			}
			CardInfo cardInfo = GetCardInfo();
			if ((Object)(object)cardInfo != (Object)null)
			{
				CardDeleteLog.Line("Hover (delete mode): '" + cardInfo.cardName + "'");
			}
		}
	}

	public void OnPointerExit(PointerEventData eventData)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_icon != (Object)null)
		{
			((Graphic)_icon).color = _originalColor;
		}
	}

	public void OnPointerClick(PointerEventData eventData)
	{
		CardDeleteLog.Section("Card bar click");
		if (!CardDeleteManager.isPickPhase)
		{
			CardDeleteLog.Line("Ignored: not in pick phase.");
			return;
		}
		if (!CardDeleteManager.IsLocalPlayerTurn())
		{
			CardDeleteLog.Line("Ignored: not local player's turn.");
			return;
		}
		if ((Object)(object)((Component)this).GetComponent<CardBarButton>() == (Object)null)
		{
			CardDeleteLog.Warn("Ignored: no CardBarButton on this object.");
			return;
		}
		CardInfo cardInfo = GetCardInfo();
		if ((Object)(object)cardInfo == (Object)null)
		{
			CardDeleteLog.Warn("Ignored: CardBarButton.card is null.");
			return;
		}
		CardDeleteLog.Line("Valid delete click on '" + cardInfo.cardName + "'.");
		CardDeleteManager.instance?.RequestDelete(cardInfo);
	}

	private CardInfo GetCardInfo()
	{
		CardBarButton component = ((Component)this).GetComponent<CardBarButton>();
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		object? value = s_cardField.GetValue(component);
		return (CardInfo)((value is CardInfo) ? value : null);
	}

	private void OnDestroy()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_icon != (Object)null)
		{
			((Graphic)_icon).color = _originalColor;
		}
	}
}
public class CardDeleteManager : MonoBehaviour
{
	public static CardDeleteManager instance;

	public static bool isPickPhase;

	public static int currentPickerID = -1;

	private static readonly MethodInfo s_rpca_assignCard = AccessTools.Method(typeof(Cards), "RPCA_AssignCard", new Type[7]
	{
		typeof(string),
		typeof(int),
		typeof(bool),
		typeof(string),
		typeof(float),
		typeof(float),
		typeof(bool)
	}, (Type[])null);

	private static readonly MethodInfo s_rpca_donePicking = AccessTools.Method(typeof(CardChoice), "RPCA_DonePicking", (Type[])null, (Type[])null);

	private static readonly FieldInfo s_spawnedCardsField = AccessTools.Field(typeof(CardChoice), "spawnedCards");

	private static readonly FieldInfo s_isPlayingField = AccessTools.Field(typeof(CardChoice), "isPlaying");

	private static readonly FieldInfo s_picksField = AccessTools.Field(typeof(CardChoice), "picks");

	private static readonly FieldInfo s_cardBarButtonCard = AccessTools.Field(typeof(CardBarButton), "card");

	private static MethodInfo s_photonDestroy;

	private static PropertyInfo s_photonOfflineMode;

	private void Start()
	{
		instance = this;
		GameModeManager.AddHook("PlayerPickStart", (Func<IGameModeHandler, IEnumerator>)OnPlayerPickStart);
		GameModeManager.AddHook("PlayerPickEnd", (Func<IGameModeHandler, IEnumerator>)OnPlayerPickEnd);
		CardDeleteLog.Section("CardDeleteManager initialized");
	}

	private IEnumerator OnPlayerPickStart(IGameModeHandler gm)
	{
		CardDeleteLog.Section("HookPlayerPickStart (info only)");
		CardDeleteLog.Line("gameMode=" + (((gm != null) ? gm.Name : null) ?? "unknown"));
		yield break;
	}

	private IEnumerator OnPlayerPickEnd(IGameModeHandler gm)
	{
		CardDeleteLog.Section("Pick phase ended (HookPlayerPickEnd)");
		CardDeleteLog.Line($"Was picker playerID={currentPickerID}");
		isPickPhase = false;
		currentPickerID = -1;
		DisableDeleteMode();
		yield break;
	}

	public void BeginPickPhase(int pickerID, string source)
	{
		if (pickerID < 0)
		{
			CardDeleteLog.Warn($"BeginPickPhase ignored (pickerID={pickerID}).");
			return;
		}
		if (isPickPhase && currentPickerID == pickerID)
		{
			CardDeleteLog.Line($"BeginPickPhase skipped — already active for player {pickerID}.");
			return;
		}
		currentPickerID = pickerID;
		isPickPhase = true;
		CardDeleteLog.Section("Pick phase active");
		CardDeleteLog.Line($"pickerID={pickerID}, source={source}");
		EnableDeleteMode(pickerID);
	}

	public void RequestDelete(CardInfo card)
	{
		CardDeleteLog.Section("Delete requested (local click)");
		CardDeleteLog.Line($"Card='{card?.cardName}', pickerID={currentPickerID}");
		NetworkingManager.RPC(typeof(CardDeleteManager), "URPC_SyncDelete", new object[2]
		{
			currentPickerID,
			((Object)card).name
		});
	}

	[UnboundRPC]
	public static void URPC_SyncDelete(int playerID, string cardObjectName)
	{
		CardDeleteLog.Section("URPC_SyncDelete (all clients)");
		CardDeleteLog.Line($"playerID={playerID}, card='{cardObjectName}'");
		Player val = PlayerManager.instance.players.Find((Player p) => p.playerID == playerID);
		if ((Object)(object)val == (Object)null)
		{
			CardDeleteLog.Error($"Player {playerID} not found.");
			return;
		}
		CardInfo val2 = val.data.currentCards?.Find((CardInfo c) => (Object)(object)c != (Object)null && ((Object)c).name == cardObjectName);
		if ((Object)(object)val2 == (Object)null)
		{
			CardDeleteLog.Error($"Card '{cardObjectName}' not found on player {playerID}.");
			EndPickPhase();
			return;
		}
		try
		{
			Cards.instance.RemoveCardFromPlayer(val, val2, (SelectionType)2);
			CardDeleteLog.Line("Removed '" + cardObjectName + "' via RemoveCardFromPlayer.");
		}
		catch (Exception arg)
		{
			CardDeleteLog.Error($"RemoveCardFromPlayer failed: {arg}");
			FallbackRemove(val, cardObjectName);
		}
		EndPickPhase();
	}

	private static void FallbackRemove(Player player, string cardObjectName)
	{
		CardDeleteLog.Warn("Using fallback removal method.");
		List<string> list = (from c in player.data.currentCards ?? new List<CardInfo>()
			where (Object)(object)c != (Object)null && ((Object)c).name != cardObjectName
			select ((Object)c).name).ToList();
		try
		{
			Cards.RPCA_FullReset(player.playerID);
		}
		catch (Exception ex)
		{
			CardDeleteLog.Error("FullReset: " + ex.Message);
		}
		try
		{
			Cards.RPCA_ClearCardBar(player.playerID);
		}
		catch (Exception ex2)
		{
			CardDeleteLog.Error("ClearCardBar: " + ex2.Message);
		}
		if (s_rpca_assignCard == null)
		{
			CardDeleteLog.Error("RPCA_AssignCard not found.");
			return;
		}
		foreach (string item in list)
		{
			try
			{
				s_rpca_assignCard.Invoke(null, new object[7] { item, player.playerID, false, "", 0f, 0f, true });
				CardDeleteLog.Line("Reapplied '" + item + "'.");
			}
			catch (Exception ex3)
			{
				CardDeleteLog.Error("Failed to reapply '" + item + "': " + ex3.Message);
			}
		}
	}

	private static void EndPickPhase()
	{
		CardDeleteLog.Section("EndPickPhase");
		CardChoice val = CardChoice.instance;
		if ((Object)(object)val == (Object)null)
		{
			CardDeleteLog.Error("CardChoice.instance is null.");
			return;
		}
		((MonoBehaviour)val).StopAllCoroutines();
		s_isPlayingField?.SetValue(val, false);
		s_picksField?.SetValue(val, 0);
		CleanupSpawnedDraftCards(val);
		if (s_rpca_donePicking != null)
		{
			try
			{
				s_rpca_donePicking.Invoke(val, null);
				CardDeleteLog.Line("Invoked RPCA_DonePicking.");
				return;
			}
			catch (Exception ex)
			{
				CardDeleteLog.Error("RPCA_DonePicking failed: " + ex.Message);
				val.IsPicking = false;
				return;
			}
		}
		val.IsPicking = false;
	}

	private static void CleanupSpawnedDraftCards(CardChoice cc)
	{
		if (s_spawnedCardsField == null || !(s_spawnedCardsField.GetValue(cc) is List<GameObject> list) || list.Count == 0)
		{
			return;
		}
		CardDeleteLog.Line($"Cleaning {list.Count} draft card(s).");
		foreach (GameObject item in list.ToList())
		{
			if ((Object)(object)item == (Object)null)
			{
				continue;
			}
			try
			{
				CardVisuals componentInChildren = item.GetComponentInChildren<CardVisuals>();
				if (componentInChildren != null)
				{
					componentInChildren.Leave();
				}
			}
			catch
			{
			}
			DestroyDraftCardObject(item);
		}
		list.Clear();
	}

	private static void DestroyDraftCardObject(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return;
		}
		try
		{
			if (TryPhotonDestroy(go))
			{
				return;
			}
		}
		catch
		{
		}
		Object.Destroy((Object)(object)go);
	}

	private static bool TryPhotonDestroy(GameObject go)
	{
		if (s_photonDestroy == null)
		{
			Type type = AccessTools.TypeByName("Photon.Pun.PhotonNetwork");
			if (type == null)
			{
				return false;
			}
			s_photonOfflineMode = type.GetProperty("OfflineMode", BindingFlags.Static | BindingFlags.Public);
			s_photonDestroy = type.GetMethod("Destroy", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(GameObject) }, null);
		}
		if (s_photonDestroy == null)
		{
			return false;
		}
		if (s_photonOfflineMode != null && (bool)s_photonOfflineMode.GetValue(null, null))
		{
			return false;
		}
		Type type2 = AccessTools.TypeByName("Photon.Pun.PhotonView");
		if (type2 == null || (Object)(object)go.GetComponent(type2) == (Object)null)
		{
			return false;
		}
		s_photonDestroy.Invoke(null, new object[1] { go });
		return true;
	}

	private void EnableDeleteMode(int pickerID)
	{
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Expected O, but got Unknown
		if ((Object)(object)CardBarHandler.instance == (Object)null)
		{
			CardDeleteLog.Warn("CardBarHandler.instance is null.");
			return;
		}
		CardBar[] value = Traverse.Create((object)CardBarHandler.instance).Field("cardBars").GetValue<CardBar[]>();
		if (value == null || pickerID < 0 || pickerID >= value.Length)
		{
			CardDeleteLog.Warn($"Invalid pickerID={pickerID}.");
			return;
		}
		int num = 0;
		foreach (Transform item in ((Component)value[pickerID]).transform)
		{
			Transform val = item;
			if (((Component)val).gameObject.activeSelf)
			{
				CardBarButton component = ((Component)val).GetComponent<CardBarButton>();
				if (!((Object)(object)component == (Object)null) && !((Object)/*isinst with value type is only supported in some contexts*/ == (Object)null) && (Object)(object)((Component)val).GetComponent<CardBarDeleteButton>() == (Object)null)
				{
					((Component)val).gameObject.AddComponent<CardBarDeleteButton>();
					num++;
				}
			}
		}
		CardDeleteLog.Line($"EnableDeleteMode: attached={num} for player {pickerID}.");
	}

	private void DisableDeleteMode()
	{
		CardBarDeleteButton[] array = Object.FindObjectsOfType<CardBarDeleteButton>();
		CardBarDeleteButton[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			Object.Destroy((Object)(object)array2[i]);
		}
		CardDeleteLog.Line($"DisableDeleteMode: removed {array.Length} button(s).");
	}

	public static bool IsLocalPlayerTurn()
	{
		if (currentPickerID < 0)
		{
			return false;
		}
		Player val = PlayerManager.instance.players.Find((Player p) => p.playerID == currentPickerID);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		object value = AccessTools.Field(typeof(CharacterData), "view").GetValue(val.data);
		if (value == null)
		{
			return true;
		}
		return (bool)AccessTools.Property(value.GetType(), "IsMine").GetValue(value, null);
	}
}
[HarmonyPatch]
internal static class CardDeletePatches
{
	[HarmonyPatch(typeof(CardChoiceVisuals), "Show")]
	[HarmonyPrefix]
	private static void CardChoiceVisuals_Show_Prefix(int pickerID, bool animateIn)
	{
		CardDeleteManager.instance?.BeginPickPhase(pickerID, "CardChoiceVisuals.Show");
	}

	[HarmonyPatch(typeof(CardChoice), "StartPick")]
	[HarmonyPostfix]
	private static void CardChoice_StartPick_Postfix(int picksToSet, int pickerIDToSet)
	{
		CardDeleteManager.instance?.BeginPickPhase(pickerIDToSet, "CardChoice.StartPick");
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("Rounds2Mod", "Mod for ROUNDS", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
	internal static ManualLogSource Logger;

	private void Awake()
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		Logger = ((BaseUnityPlugin)this).Logger;
		CardDeleteLog.Section("Plugin Awake");
		new Harmony("Rounds2Mod").PatchAll();
		((Component)this).gameObject.AddComponent<CardDeleteManager>();
		CardDeleteLog.Line("Plugin Rounds2Mod loaded.");
	}
}