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(); 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() == (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(); 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 d__13 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IGameModeHandler gm; public CardDeleteManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 d__11 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IGameModeHandler gm; public CardDeleteManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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)OnPlayerPickStart); GameModeManager.AddHook("PlayerPickEnd", (Func)OnPlayerPickEnd); CardDeleteLog.Section("CardDeleteManager initialized"); CardDeleteLog.Line("Registered HookPlayerPickStart / HookPlayerPickEnd."); } [IteratorStateMachine(typeof(d__11))] private IEnumerator OnPlayerPickStart(IGameModeHandler gm) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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(d__13))] private IEnumerator OnPlayerPickEnd(IGameModeHandler gm) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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(); 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(); 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() == (Object)null) { ((Component)val2).gameObject.AddComponent(); 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().Length; CardBarDeleteButton[] array = Object.FindObjectsOfType(); 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 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 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(); 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(); 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"; } }