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 Microsoft.CodeAnalysis;
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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: AssemblyCompany("Rounds2Mod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+661a91535814621160b5d94d61679bade4fe1c2d")]
[assembly: AssemblyProduct("Mod for ROUNDS")]
[assembly: AssemblyTitle("Rounds2Mod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 Rounds2Mod
{
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_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: 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_004c: 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 + "' on '" + ((Object)((Component)this).gameObject).name + "'");
}
}
}
public void OnPointerExit(PointerEventData eventData)
{
//IL_0018: 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 + "' (objectName='" + ((Object)cardInfo).name + "').");
CardDeleteManager.instance?.RequestDelete(cardInfo);
}
private CardInfo GetCardInfo()
{
CardBarButton component = ((Component)this).GetComponent<CardBarButton>();
return (CardInfo)(((Object)(object)component == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
}
private void OnDestroy()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)icon != (Object)null)
{
((Graphic)icon).color = originalColor;
}
}
}
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 CardDeleteManager : MonoBehaviour
{
[CompilerGenerated]
private sealed class <OnPlayerPickEnd>d__13 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public IGameModeHandler gm;
public CardDeleteManager <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnPlayerPickEnd>d__13(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
if (<>1__state != 0)
{
return false;
}
<>1__state = -1;
CardDeleteLog.Section("Pick phase ended (HookPlayerPickEnd)");
CardDeleteLog.Line($"Was picker playerID={currentPickerID}");
isPickPhase = false;
currentPickerID = -1;
<>4__this.DisableDeleteMode();
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <OnPlayerPickStart>d__11 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public IGameModeHandler gm;
public CardDeleteManager <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnPlayerPickStart>d__11(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
if (<>1__state != 0)
{
return false;
}
<>1__state = -1;
CardDeleteLog.Section("HookPlayerPickStart (info only)");
IGameModeHandler obj = gm;
CardDeleteLog.Line("gameMode=" + (((obj != null) ? obj.Name : null) ?? "unknown") + "; waiting for Harmony Show/StartPick patch to fire.");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
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 MethodInfo s_photonDestroy;
private static PropertyInfo s_photonOfflineMode;
private static readonly FieldInfo s_cardBarButtonCard = AccessTools.Field(typeof(CardBarButton), "card");
private void Start()
{
instance = this;
GameModeManager.AddHook("PlayerPickStart", (Func<IGameModeHandler, IEnumerator>)OnPlayerPickStart);
GameModeManager.AddHook("PlayerPickEnd", (Func<IGameModeHandler, IEnumerator>)OnPlayerPickEnd);
CardDeleteLog.Section("CardDeleteManager initialized");
CardDeleteLog.Line("Registered HookPlayerPickStart / HookPlayerPickEnd.");
}
[IteratorStateMachine(typeof(<OnPlayerPickStart>d__11))]
private IEnumerator OnPlayerPickStart(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnPlayerPickStart>d__11(0)
{
<>4__this = this,
gm = gm
};
}
public void BeginPickPhase(int pickerID, string source)
{
if (pickerID < 0)
{
CardDeleteLog.Warn($"BeginPickPhase ignored (pickerID={pickerID}, source={source}).");
return;
}
if (isPickPhase && currentPickerID == pickerID)
{
CardDeleteLog.Line($"BeginPickPhase skipped — already active for player {pickerID} (source={source}).");
return;
}
currentPickerID = pickerID;
isPickPhase = true;
CardDeleteLog.Section("Pick phase active");
CardDeleteLog.Line($"pickerID={pickerID}, source={source}");
CardDeleteLog.Line($"IsPicking={CardChoice.instance?.IsPicking}, pickrID={CardChoice.instance?.pickrID}, localTurn={IsLocalPlayerTurn()}");
EnableDeleteMode(pickerID);
}
[IteratorStateMachine(typeof(<OnPlayerPickEnd>d__13))]
private IEnumerator OnPlayerPickEnd(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnPlayerPickEnd>d__13(0)
{
<>4__this = this,
gm = gm
};
}
private void EnableDeleteMode(int pickerID)
{
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Expected O, but got Unknown
if ((Object)(object)CardBarHandler.instance == (Object)null)
{
CardDeleteLog.Warn("EnableDeleteMode: 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($"EnableDeleteMode: invalid pickerID={pickerID}, bars={((value != null) ? value.Length : 0)}");
return;
}
int num = 0;
int num2 = 0;
int num3 = 0;
CardBar val = value[pickerID];
foreach (Transform item in ((Component)val).transform)
{
Transform val2 = item;
if (!((Component)val2).gameObject.activeSelf)
{
num2++;
continue;
}
CardBarButton component = ((Component)val2).GetComponent<CardBarButton>();
if (!((Object)(object)component == (Object)null))
{
object? obj = s_cardBarButtonCard?.GetValue(component);
CardInfo val3 = (CardInfo)((obj is CardInfo) ? obj : null);
if ((Object)(object)val3 == (Object)null)
{
num3++;
}
else if ((Object)(object)((Component)val2).GetComponent<CardBarDeleteButton>() == (Object)null)
{
((Component)val2).gameObject.AddComponent<CardBarDeleteButton>();
num++;
}
}
}
CardDeleteLog.Line($"EnableDeleteMode: attached={num}, skipped(inactive)={num2}, skipped(noCard)={num3} for player {pickerID}.");
if (num == 0)
{
CardDeleteLog.Line("Player has no deletable cards this turn (deck is empty).");
}
}
private void DisableDeleteMode()
{
int num = Object.FindObjectsOfType<CardBarDeleteButton>().Length;
CardBarDeleteButton[] array = Object.FindObjectsOfType<CardBarDeleteButton>();
foreach (CardBarDeleteButton cardBarDeleteButton in array)
{
Object.Destroy((Object)(object)cardBarDeleteButton);
}
CardDeleteLog.Line($"DisableDeleteMode: removed {num} CardBarDeleteButton component(s).");
}
public void RequestDelete(CardInfo card)
{
CardDeleteLog.Section("Delete requested (local click)");
CardDeleteLog.Line($"Card='{card?.cardName}' objectName='{((card != null) ? ((Object)card).name : null)}', pickerID={currentPickerID}");
CardDeleteLog.Line("Broadcasting URPC_SyncDelete to all clients.");
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}, deleteCardObjectName='{cardObjectName}'");
Player val = PlayerManager.instance.players.Find((Player p) => p.playerID == playerID);
if ((Object)(object)val == (Object)null)
{
CardDeleteLog.Error($"URPC_SyncDelete: player {playerID} not found.");
return;
}
int num = val.data.currentCards?.Count ?? 0;
List<string> list = (from c in val.data.currentCards
where (Object)(object)c != (Object)null && ((Object)c).name != cardObjectName
select ((Object)c).name).ToList();
CardDeleteLog.Section("Deletion logic — snapshot");
CardDeleteLog.Line($"currentCards before reset: {num}");
CardDeleteLog.Line("Removing: '" + cardObjectName + "'");
CardDeleteLog.Line(string.Format("Survivors to reapply ({0}): [{1}]", list.Count, string.Join(", ", list)));
CardDeleteLog.Section("Deletion logic — stat reset");
try
{
Cards.RPCA_FullReset(playerID);
CardDeleteLog.Line("RPCA_FullReset completed.");
}
catch (Exception arg)
{
CardDeleteLog.Error($"RPCA_FullReset failed: {arg}");
}
try
{
Cards.RPCA_ClearCardBar(playerID);
CardDeleteLog.Line("RPCA_ClearCardBar completed.");
}
catch (Exception arg2)
{
CardDeleteLog.Error($"RPCA_ClearCardBar failed: {arg2}");
}
CardDeleteLog.Section("Deletion logic — reapply survivors");
if (s_rpca_assignCard == null)
{
CardDeleteLog.Error("RPCA_AssignCard not found via reflection.");
}
else
{
foreach (string item in list)
{
try
{
s_rpca_assignCard.Invoke(null, new object[7] { item, playerID, true, "", 0f, 0f, true });
CardDeleteLog.Line("Reapplied '" + item + "' (reassign=true).");
}
catch (Exception arg3)
{
CardDeleteLog.Error($"Failed to reapply '{item}': {arg3}");
}
}
}
CardDeleteLog.Line($"currentCards after reapply: {val.data.currentCards?.Count ?? 0}");
EndPickPhase();
}
private static void EndPickPhase()
{
CardDeleteLog.Section("EndPickPhase");
CardChoice val = CardChoice.instance;
if ((Object)(object)val == (Object)null)
{
CardDeleteLog.Error("CardChoice.instance is null.");
return;
}
CardDeleteLog.Line($"Before: IsPicking={val.IsPicking}, pickrID={val.pickrID}");
((MonoBehaviour)val).StopAllCoroutines();
CardDeleteLog.Line("Stopped all CardChoice coroutines.");
if (s_isPlayingField != null)
{
s_isPlayingField.SetValue(val, false);
}
if (s_picksField != null)
{
s_picksField.SetValue(val, 0);
}
CleanupSpawnedDraftCards(val);
if (s_rpca_donePicking == null)
{
CardDeleteLog.Warn("RPCA_DonePicking not found; falling back to IsPicking=false.");
val.IsPicking = false;
}
else
{
try
{
s_rpca_donePicking.Invoke(val, null);
CardDeleteLog.Line("Invoked CardChoice.RPCA_DonePicking().");
}
catch (Exception arg)
{
CardDeleteLog.Error($"RPCA_DonePicking failed: {arg}; setting IsPicking=false directly.");
val.IsPicking = false;
}
}
CardDeleteLog.Line($"After: IsPicking={val.IsPicking}");
}
private static void CleanupSpawnedDraftCards(CardChoice cc)
{
CardDeleteLog.Section("EndPickPhase — cleanup draft cards");
if (s_spawnedCardsField == null)
{
CardDeleteLog.Warn("spawnedCards field not found.");
return;
}
if (!(s_spawnedCardsField.GetValue(cc) is List<GameObject> list) || list.Count == 0)
{
CardDeleteLog.Line("No spawned draft cards to clean up.");
return;
}
CardDeleteLog.Line($"Cleaning {list.Count} spawned draft card(s).");
foreach (GameObject item in list.ToList())
{
if ((Object)(object)item == (Object)null)
{
continue;
}
try
{
CardVisuals componentInChildren = item.GetComponentInChildren<CardVisuals>();
if ((Object)(object)componentInChildren != (Object)null)
{
componentInChildren.Leave();
}
}
catch (Exception ex)
{
CardDeleteLog.Warn("CardVisuals.Leave on '" + ((Object)item).name + "': " + ex.Message);
}
DestroyDraftCardObject(item);
}
list.Clear();
CardDeleteLog.Line("spawnedCards cleared.");
}
private static void DestroyDraftCardObject(GameObject go)
{
if ((Object)(object)go == (Object)null)
{
return;
}
try
{
if (TryPhotonDestroy(go))
{
CardDeleteLog.Line("Photon-destroyed draft card '" + ((Object)go).name + "'.");
return;
}
}
catch (Exception ex)
{
CardDeleteLog.Warn("Photon destroy failed for '" + ((Object)go).name + "': " + ex.Message);
}
Object.Destroy((Object)(object)go);
CardDeleteLog.Line("Destroyed draft card '" + ((Object)go).name + "' locally.");
}
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)
{
return false;
}
if ((Object)(object)go.GetComponent(type2) == (Object)null)
{
return false;
}
s_photonDestroy.Invoke(null, new object[1] { go });
return true;
}
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_001c: 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.");
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "Rounds2Mod";
public const string PLUGIN_NAME = "Mod for ROUNDS";
public const string PLUGIN_VERSION = "1.0.0";
}
}