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.");
}
}