using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("NoDisconnectRestart")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NoDisconnectRestart")]
[assembly: AssemblyTitle("NoDisconnectRestart")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace NoDisconnectRestart;
[BepInPlugin("com.sparky777.rounds.nodisconnectrestart", "NoDisconnectRestart", "2.5.0")]
public class NoDisconnectRestartPlugin : BaseUnityPlugin
{
public const string ModId = "com.sparky777.rounds.nodisconnectrestart";
public const string ModName = "NoDisconnectRestart";
public const string ModVersion = "2.5.0";
internal static ManualLogSource Log;
private Harmony _harmony;
private void Awake()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
_harmony = new Harmony("com.sparky777.rounds.nodisconnectrestart");
_harmony.PatchAll(typeof(NoDisconnectRestartPlugin).Assembly);
Log.LogInfo((object)"NoDisconnectRestart 2.5.0 loaded.");
}
private void Start()
{
ApplyRWFPatches();
}
private void ApplyRWFPatches()
{
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Expected O, but got Unknown
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Expected O, but got Unknown
//IL_0177: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Expected O, but got Unknown
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Expected O, but got Unknown
//IL_0299: Unknown result type (might be due to invalid IL or missing references)
//IL_02a7: Expected O, but got Unknown
//IL_0330: Unknown result type (might be due to invalid IL or missing references)
//IL_033e: Expected O, but got Unknown
//IL_0387: Unknown result type (might be due to invalid IL or missing references)
//IL_0395: Expected O, but got Unknown
//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0408: Expected O, but got Unknown
Type type = AccessTools.TypeByName("Photon.Pun.PhotonNetwork") ?? AccessTools.TypeByName("PhotonNetwork");
if (type != null)
{
MethodInfo methodInfo = AccessTools.Method(type, "LoadLevel", new Type[1] { typeof(string) }, (Type[])null) ?? AccessTools.Method(type, "LoadLevel", new Type[1] { typeof(int) }, (Type[])null);
if (methodInfo != null)
{
_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patch_PhotonNetwork_LoadLevel), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched PhotonNetwork.LoadLevel");
}
}
Type type2 = AccessTools.TypeByName("NetworkConnectionHandler");
if (type2 != null)
{
MethodInfo methodInfo2 = AccessTools.Method(type2, "OnDisconnected", (Type[])null, (Type[])null);
if (methodInfo2 != null)
{
_harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(Patch_OnDisconnected), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched NetworkConnectionHandler.OnDisconnected");
}
}
Type type3 = AccessTools.TypeByName("PlayerManager");
if (type3 != null)
{
MethodInfo methodInfo3 = AccessTools.Method(type3, "ResetCharacters", (Type[])null, (Type[])null);
if (methodInfo3 != null)
{
_harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(Patch_PlayerManager_ResetCharacters), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched PlayerManager.ResetCharacters");
}
}
Type typeFromHandle = typeof(SceneManager);
MethodInfo methodInfo4 = AccessTools.Method(typeFromHandle, "LoadScene", new Type[1] { typeof(string) }, (Type[])null) ?? AccessTools.Method(typeFromHandle, "LoadScene", new Type[1] { typeof(int) }, (Type[])null);
if (methodInfo4 != null)
{
_harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(Patch_SceneManager_LoadScene), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched SceneManager.LoadScene");
}
MethodInfo methodInfo5 = AccessTools.Method(typeFromHandle, "LoadSceneAsync", new Type[1] { typeof(string) }, (Type[])null) ?? AccessTools.Method(typeFromHandle, "LoadSceneAsync", new Type[1] { typeof(int) }, (Type[])null);
if (methodInfo5 != null)
{
_harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(typeof(Patch_SceneManager_LoadSceneAsync), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched SceneManager.LoadSceneAsync");
}
Type type4 = AccessTools.TypeByName("RWF.GameModes.RWFGameMode") ?? AccessTools.TypeByName("RWFGameMode");
if (type4 == null)
{
Log.LogWarning((object)"[NDR] RWFGameMode not found.");
}
else
{
MethodInfo methodInfo6 = AccessTools.Method(type4, "ResetMatch", (Type[])null, (Type[])null);
if (methodInfo6 != null)
{
_harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(typeof(Patch_RWFGameMode_ResetMatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched RWFGameMode.ResetMatch");
}
MethodInfo methodInfo7 = AccessTools.Method(type4, "OnDisable", (Type[])null, (Type[])null);
if (methodInfo7 != null)
{
_harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(typeof(Patch_RWFGameMode_OnDisable), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched RWFGameMode.OnDisable");
}
}
Type type5 = AccessTools.TypeByName("RWF.PointVisualizerExtensions");
if (type5 != null)
{
MethodInfo methodInfo8 = AccessTools.Method(type5, "ResetBalls", (Type[])null, (Type[])null);
if (methodInfo8 != null)
{
_harmony.Patch((MethodBase)methodInfo8, new HarmonyMethod(typeof(Patch_PointVisualizer_ResetBalls), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"[NDR] Patched PointVisualizerExtensions.ResetBalls");
}
}
TryPatch(new string[2] { "CardChoiceVisuals", "CardChoice" }, new string[4] { "PlayerLeftInPickPhase", "CheckPlayerCount", "OnPlayerLeft", "PlayerLeft" }, "Patch_CardPickDisconnect", "Prefix");
TryPatch(new string[3] { "GameManager", "GM", "RoundHandler" }, new string[4] { "RoundOver", "OnRoundEnd", "RoundEnd", "PointOver" }, "Patch_RoundEnd", "Postfix", isPrefix: false, isPostfix: true);
TryPatch(new string[2] { "NetworkConnectionHandler", "RoundsNetworkConnectionHandler" }, new string[3] { "OnPlayerEnteredRoom", "PlayerEnteredRoom", "OnPlayerJoined" }, "Patch_OnPlayerEnteredRoom", "Postfix", isPrefix: false, isPostfix: true);
TryPatch(new string[2] { "CardChoice", "CardChoiceVisuals" }, new string[5] { "StartPick", "DoPick", "StartCardPick", "StartPickPhase", "Pick" }, "Patch_CardPickPhaseStart", "Postfix", isPrefix: false, isPostfix: true);
void TryPatch(string[] typeNames, string[] methodNames, string patchClass, string patchMethod, bool isPrefix = true, bool isPostfix = false)
{
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
foreach (string text in typeNames)
{
Type type6 = AccessTools.TypeByName(text);
if (!(type6 == null))
{
foreach (string text2 in methodNames)
{
MethodInfo methodInfo9 = AccessTools.Method(type6, text2, (Type[])null, (Type[])null);
if (!(methodInfo9 == null))
{
try
{
Type type7 = Type.GetType("NoDisconnectRestart." + patchClass + ", NoDisconnectRestart");
if (!(type7 == null))
{
HarmonyMethod val = ((!isPrefix) ? ((HarmonyMethod)null) : new HarmonyMethod(type7, patchMethod, (Type[])null));
HarmonyMethod val2 = ((!isPostfix) ? ((HarmonyMethod)null) : new HarmonyMethod(type7, patchMethod, (Type[])null));
_harmony.Patch((MethodBase)methodInfo9, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)("[NDR] Patched " + text + "." + text2 + " -> " + patchClass + "." + patchMethod));
}
return;
}
catch (Exception ex)
{
Log.LogWarning((object)("[NDR] Failed to patch " + text + "." + text2 + ": " + ex.Message));
}
}
}
}
}
}
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
public static class PlayerStateTracker
{
public static Dictionary<int, PlayerSnapshot> Snapshots = new Dictionary<int, PlayerSnapshot>();
public static Dictionary<int, int> MissedRounds = new Dictionary<int, int>();
public static int CurrentRound = 0;
public static void SaveSnapshot(int actorNumber, PlayerSnapshot snap)
{
Snapshots[actorNumber] = snap;
MissedRounds[actorNumber] = 0;
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Saved snapshot for actor {actorNumber} — {snap.CardNames.Count} cards.");
}
public static void IncrementMissedRounds()
{
CurrentRound++;
List<int> list = new List<int>(MissedRounds.Keys);
foreach (int item in list)
{
MissedRounds[item]++;
}
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Round {CurrentRound} ended. Tracking {MissedRounds.Count} absent player(s).");
}
public static bool TryGetSnapshot(int actorNumber, out PlayerSnapshot snap)
{
return Snapshots.TryGetValue(actorNumber, out snap);
}
public static int GetMissedRounds(int actorNumber)
{
int value;
return MissedRounds.TryGetValue(actorNumber, out value) ? value : 0;
}
public static void ClearPlayer(int actorNumber)
{
Snapshots.Remove(actorNumber);
MissedRounds.Remove(actorNumber);
}
public static void Reset()
{
Snapshots.Clear();
MissedRounds.Clear();
CurrentRound = 0;
}
}
public class PlayerSnapshot
{
public List<string> CardNames = new List<string>();
public int TeamIndex;
public int ActorNumber;
}
[HarmonyPatch]
public static class Patch_OnPlayerLeftRoom
{
private static MethodBase TargetMethod()
{
string[] array = new string[2] { "NetworkConnectionHandler", "RoundsNetworkConnectionHandler" };
string[] array2 = new string[3] { "OnPlayerLeftRoom", "PlayerLeftRoom", "OnPlayerDisconnected" };
string[] array3 = array;
foreach (string text in array3)
{
Type type = AccessTools.TypeByName(text);
if (type == null)
{
continue;
}
string[] array4 = array2;
foreach (string text2 in array4)
{
MethodInfo methodInfo = AccessTools.Method(type, text2, (Type[])null, (Type[])null);
if (methodInfo != null)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)("[NDR] Patching " + text + "." + text2));
return methodInfo;
}
}
}
NoDisconnectRestartPlugin.Log.LogWarning((object)"[NDR] OnPlayerLeftRoom not found.");
return null;
}
private static bool Prefix(object __instance, object otherPlayer)
{
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Expected O, but got Unknown
if (otherPlayer == null)
{
return false;
}
Type type = otherPlayer.GetType();
string arg = type.GetProperty("NickName")?.GetValue(otherPlayer)?.ToString() ?? "unknown";
int num = (int)(type.GetProperty("ActorNumber")?.GetValue(otherPlayer) ?? ((object)0));
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Player left: {arg} (actor {num}) — suppressing restart.");
DisconnectGuard.DisconnectInProgress = true;
GameObject val = new GameObject("NDR_DisconnectGuardClearer");
val.AddComponent<DisconnectGuardClearer>();
Object.DontDestroyOnLoad((Object)(object)val);
if (num > 0)
{
CardSaver.TrySavePlayerCards(num);
}
return false;
}
}
public class DisconnectGuardClearer : MonoBehaviour
{
private void Start()
{
((MonoBehaviour)this).StartCoroutine(Clear());
}
private IEnumerator Clear()
{
yield return (object)new WaitForSeconds(30f);
DisconnectGuard.DisconnectInProgress = false;
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Disconnect guard cleared.");
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
public static class DisconnectGuard
{
public static bool DisconnectInProgress;
}
public static class Patch_PhotonNetwork_LoadLevel
{
public static bool Prefix()
{
if (DisconnectGuard.DisconnectInProgress)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Blocked PhotonNetwork.LoadLevel from disconnect.");
return false;
}
return true;
}
}
public static class Patch_OnDisconnected
{
public static bool Prefix()
{
if (DisconnectGuard.DisconnectInProgress)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Blocked OnDisconnected callback from disconnect.");
return false;
}
return true;
}
}
public static class Patch_PlayerManager_ResetCharacters
{
public static bool Prefix()
{
if (DisconnectGuard.DisconnectInProgress)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Blocked PlayerManager.ResetCharacters from disconnect.");
return false;
}
return true;
}
}
public static class Patch_SceneManager_LoadScene
{
public static bool Prefix()
{
StackTrace stackTrace = new StackTrace();
StringBuilder stringBuilder = new StringBuilder("[NDR] SceneManager.LoadScene called from:\n");
for (int i = 0; i < Math.Min(stackTrace.FrameCount, 12); i++)
{
MethodBase methodBase = stackTrace.GetFrame(i)?.GetMethod();
if (methodBase != null)
{
stringBuilder.AppendLine($" [{i}] {methodBase.DeclaringType?.Name}.{methodBase.Name}");
}
}
NoDisconnectRestartPlugin.Log.LogInfo((object)stringBuilder.ToString());
if (DisconnectGuard.DisconnectInProgress)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Blocked scene reload from disconnect.");
return false;
}
return true;
}
}
public static class Patch_SceneManager_LoadSceneAsync
{
public static bool Prefix()
{
StackTrace stackTrace = new StackTrace();
StringBuilder stringBuilder = new StringBuilder("[NDR] SceneManager.LoadSceneAsync called from:\n");
for (int i = 0; i < Math.Min(stackTrace.FrameCount, 12); i++)
{
MethodBase methodBase = stackTrace.GetFrame(i)?.GetMethod();
if (methodBase != null)
{
stringBuilder.AppendLine($" [{i}] {methodBase.DeclaringType?.Name}.{methodBase.Name}");
}
}
NoDisconnectRestartPlugin.Log.LogInfo((object)stringBuilder.ToString());
if (DisconnectGuard.DisconnectInProgress)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Blocked async scene reload from disconnect.");
return false;
}
return true;
}
}
public static class Patch_RWFGameMode_ResetMatch
{
public static bool Prefix()
{
if (DisconnectGuard.DisconnectInProgress)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Blocked RWFGameMode.ResetMatch from disconnect.");
return false;
}
return true;
}
}
public static class Patch_RWFGameMode_OnDisable
{
public static bool Prefix()
{
if (DisconnectGuard.DisconnectInProgress)
{
NoDisconnectRestartPlugin.Log.LogInfo((object)"[NDR] Blocked RWFGameMode.OnDisable from disconnect.");
return false;
}
return true;
}
}
public static class Patch_PointVisualizer_ResetBalls
{
public static bool Prefix()
{
if (DisconnectGuard.DisconnectInProgress)
{
return false;
}
return true;
}
}
public static class Patch_CardPickDisconnect
{
public static bool Prefix()
{
return false;
}
}
public static class Patch_RoundEnd
{
public static void Postfix()
{
PlayerStateTracker.IncrementMissedRounds();
}
}
public static class Patch_OnPlayerEnteredRoom
{
public static void Postfix(object newPlayer)
{
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
if (newPlayer == null)
{
return;
}
Type type = newPlayer.GetType();
int num = (int)(type.GetProperty("ActorNumber")?.GetValue(newPlayer) ?? ((object)0));
if (num == 0)
{
return;
}
if (PlayerStateTracker.TryGetSnapshot(num, out var snap))
{
int missedRounds = PlayerStateTracker.GetMissedRounds(num);
string arg = newPlayer.GetType().GetProperty("NickName")?.GetValue(newPlayer)?.ToString() ?? "unknown";
NoDisconnectRestartPlugin.Log.LogInfo((object)($"[NDR] {arg} rejoined (actor {num}). " + $"Restoring {snap.CardNames.Count} cards, queuing {missedRounds} catch-up picks."));
GameObject val = new GameObject("NDR_RejoinHandler");
RejoinHandler rejoinHandler = val.AddComponent<RejoinHandler>();
rejoinHandler.ActorNumber = num;
rejoinHandler.Snapshot = snap;
rejoinHandler.MissedRounds = missedRounds;
Object.DontDestroyOnLoad((Object)(object)val);
}
else
{
int currentRound = PlayerStateTracker.CurrentRound;
if (currentRound > 0)
{
string arg2 = newPlayer.GetType().GetProperty("NickName")?.GetValue(newPlayer)?.ToString() ?? "unknown";
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Late joiner {arg2} — queuing {currentRound} catch-up picks.");
CatchupPickQueue.Enqueue(num, currentRound);
}
}
}
}
public class RejoinHandler : MonoBehaviour
{
public int ActorNumber;
public PlayerSnapshot Snapshot;
public int MissedRounds;
private void Start()
{
((MonoBehaviour)this).StartCoroutine(RestoreAfterDelay());
}
private IEnumerator RestoreAfterDelay()
{
yield return (object)new WaitForSeconds(3f);
CardRestorer.RestoreCards(ActorNumber, Snapshot);
CatchupPickQueue.Enqueue(ActorNumber, MissedRounds);
PlayerStateTracker.ClearPlayer(ActorNumber);
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
public static class CardSaver
{
public static void TrySavePlayerCards(int actorNumber)
{
try
{
Type type = AccessTools.TypeByName("PlayerManager");
if (type == null)
{
NoDisconnectRestartPlugin.Log.LogWarning((object)"[NDR] PlayerManager not found.");
return;
}
object obj = AccessTools.Field(type, "instance")?.GetValue(null);
if (obj == null)
{
NoDisconnectRestartPlugin.Log.LogWarning((object)"[NDR] PlayerManager.instance null.");
return;
}
if (!(AccessTools.Field(obj.GetType(), "players")?.GetValue(obj) is IList list))
{
NoDisconnectRestartPlugin.Log.LogWarning((object)"[NDR] PlayerManager.players null.");
return;
}
PlayerSnapshot playerSnapshot = new PlayerSnapshot
{
ActorNumber = actorNumber
};
foreach (object item in list)
{
if (item == null)
{
continue;
}
object obj2 = null;
MethodInfo method = item.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) });
if (method != null)
{
Type type2 = AccessTools.TypeByName("Photon.Pun.PhotonView") ?? AccessTools.TypeByName("PhotonView");
if (type2 != null)
{
obj2 = method.Invoke(item, new object[1] { type2 });
}
}
if (obj2 == null)
{
obj2 = AccessTools.Field(item.GetType(), "photonView")?.GetValue(item);
}
if (obj2 == null)
{
continue;
}
int num = (int)(obj2.GetType().GetProperty("OwnerActorNr")?.GetValue(obj2) ?? ((object)(-1)));
if (num != actorNumber)
{
continue;
}
object obj3 = AccessTools.Field(item.GetType(), "data")?.GetValue(item);
if (obj3 == null || !(AccessTools.Field(obj3.GetType(), "currentCards")?.GetValue(obj3) is IList list2))
{
continue;
}
foreach (object item2 in list2)
{
string text = item2?.GetType().GetProperty("cardName")?.GetValue(item2)?.ToString() ?? item2?.GetType().GetField("cardName")?.GetValue(item2)?.ToString();
if (text != null)
{
playerSnapshot.CardNames.Add(text);
}
}
MemberInfo memberInfo = (MemberInfo)(((object)AccessTools.Property(item.GetType(), "teamID")) ?? ((object)AccessTools.Field(item.GetType(), "teamID")));
if (memberInfo is PropertyInfo propertyInfo)
{
playerSnapshot.TeamIndex = (int)propertyInfo.GetValue(item);
}
else if (memberInfo is FieldInfo fieldInfo)
{
playerSnapshot.TeamIndex = (int)fieldInfo.GetValue(item);
}
break;
}
if (playerSnapshot.CardNames.Count > 0)
{
PlayerStateTracker.SaveSnapshot(actorNumber, playerSnapshot);
}
else
{
NoDisconnectRestartPlugin.Log.LogWarning((object)$"[NDR] No cards found for actor {actorNumber} — snapshot skipped.");
}
}
catch (Exception ex)
{
NoDisconnectRestartPlugin.Log.LogWarning((object)$"[NDR] Failed to save cards for actor {actorNumber}: {ex.Message}");
}
}
}
public static class CardRestorer
{
public static void RestoreCards(int actorNumber, PlayerSnapshot snap)
{
try
{
Type type = AccessTools.TypeByName("PlayerManager");
if (type == null)
{
return;
}
object obj = AccessTools.Field(type, "instance")?.GetValue(null);
if (obj == null || !(AccessTools.Field(obj.GetType(), "players")?.GetValue(obj) is IList list))
{
return;
}
object obj2 = null;
foreach (object item in list)
{
if (item == null)
{
continue;
}
object obj3 = null;
MethodInfo method = item.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) });
if (method != null)
{
Type type2 = AccessTools.TypeByName("Photon.Pun.PhotonView") ?? AccessTools.TypeByName("PhotonView");
if (type2 != null)
{
obj3 = method.Invoke(item, new object[1] { type2 });
}
}
if (obj3 == null)
{
obj3 = AccessTools.Field(item.GetType(), "photonView")?.GetValue(item);
}
if (obj3 != null)
{
int num = (int)(obj3.GetType().GetProperty("OwnerActorNr")?.GetValue(obj3) ?? ((object)(-1)));
if (num == actorNumber)
{
obj2 = item;
break;
}
}
}
if (obj2 == null)
{
NoDisconnectRestartPlugin.Log.LogWarning((object)$"[NDR] Could not find player object for actor {actorNumber}.");
return;
}
Type type3 = AccessTools.TypeByName("CardManager");
IList list2 = ((type3 == null) ? null : ((AccessTools.Property(type3, "cards")?.GetValue(null) as IList) ?? (AccessTools.Field(type3, "cards")?.GetValue(null) as IList)));
if (list2 == null)
{
NoDisconnectRestartPlugin.Log.LogWarning((object)"[NDR] Could not access CardManager.cards.");
return;
}
Dictionary<string, object> dictionary = new Dictionary<string, object>();
foreach (object item2 in list2)
{
string text = item2?.GetType().GetProperty("cardName")?.GetValue(item2)?.ToString() ?? item2?.GetType().GetField("cardName")?.GetValue(item2)?.ToString();
if (text != null && !dictionary.ContainsKey(text))
{
dictionary[text] = item2;
}
}
MethodInfo methodInfo = AccessTools.Method(obj2.GetType(), "AddCard", (Type[])null, (Type[])null) ?? AccessTools.Method(obj2.GetType(), "PickCard", (Type[])null, (Type[])null) ?? AccessTools.Method(obj2.GetType(), "AddCardToPlayer", (Type[])null, (Type[])null);
foreach (string cardName in snap.CardNames)
{
if (dictionary.TryGetValue(cardName, out var value))
{
try
{
methodInfo?.Invoke(obj2, new object[1] { value });
}
catch (Exception ex)
{
NoDisconnectRestartPlugin.Log.LogWarning((object)("[NDR] Could not apply card '" + cardName + "': " + ex.Message));
}
}
}
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Restored {snap.CardNames.Count} cards to actor {actorNumber}.");
}
catch (Exception ex2)
{
NoDisconnectRestartPlugin.Log.LogWarning((object)$"[NDR] RestoreCards failed for actor {actorNumber}: {ex2.Message}");
}
}
}
public static class CatchupPickQueue
{
public static Dictionary<int, int> PendingPicks = new Dictionary<int, int>();
public static void Enqueue(int actorNumber, int picks)
{
if (picks > 0)
{
if (PendingPicks.ContainsKey(actorNumber))
{
PendingPicks[actorNumber] += picks;
}
else
{
PendingPicks[actorNumber] = picks;
}
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Queued {picks} catch-up pick(s) for actor {actorNumber}.");
}
}
public static bool TryConsume(int actorNumber, out int picks)
{
if (PendingPicks.TryGetValue(actorNumber, out picks) && picks > 0)
{
PendingPicks.Remove(actorNumber);
return true;
}
picks = 0;
return false;
}
}
public static class Patch_CardPickPhaseStart
{
public static void Postfix(object __instance)
{
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Expected O, but got Unknown
if (CatchupPickQueue.PendingPicks.Count == 0)
{
return;
}
foreach (KeyValuePair<int, int> item in new Dictionary<int, int>(CatchupPickQueue.PendingPicks))
{
int key = item.Key;
int value = item.Value;
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Granting {value} extra pick(s) to actor {key} in this pick phase.");
MethodInfo methodInfo = AccessTools.Method(__instance.GetType(), "AddExtraPick", (Type[])null, (Type[])null) ?? AccessTools.Method(__instance.GetType(), "GiveExtraPick", (Type[])null, (Type[])null) ?? AccessTools.Method(__instance.GetType(), "AddPicks", (Type[])null, (Type[])null);
if (methodInfo != null)
{
try
{
methodInfo.Invoke(__instance, new object[2] { key, value });
}
catch
{
}
}
CatchupPickQueue.PendingPicks.Remove(key);
GameObject val = new GameObject("NDR_CatchupPick");
CatchupPickRunner catchupPickRunner = val.AddComponent<CatchupPickRunner>();
catchupPickRunner.ActorNumber = key;
catchupPickRunner.RemainingPicks = value;
catchupPickRunner.PickInstance = __instance;
Object.DontDestroyOnLoad((Object)(object)val);
}
}
}
public class CatchupPickRunner : MonoBehaviour
{
public int ActorNumber;
public int RemainingPicks;
public object PickInstance;
private void Start()
{
((MonoBehaviour)this).StartCoroutine(RunPicks());
}
private IEnumerator RunPicks()
{
for (int i = 0; i < RemainingPicks; i++)
{
yield return (object)new WaitForSeconds(1f);
NoDisconnectRestartPlugin.Log.LogInfo((object)$"[NDR] Triggering catch-up pick {i + 1}/{RemainingPicks} for actor {ActorNumber}.");
MethodInfo startPickForPlayer = AccessTools.Method(PickInstance?.GetType(), "StartPickForPlayer", (Type[])null, (Type[])null) ?? AccessTools.Method(PickInstance?.GetType(), "PickForPlayer", (Type[])null, (Type[])null) ?? AccessTools.Method(PickInstance?.GetType(), "DoPickForActor", (Type[])null, (Type[])null);
if (startPickForPlayer != null)
{
try
{
startPickForPlayer.Invoke(PickInstance, new object[1] { ActorNumber });
}
catch (Exception ex)
{
Exception ex2 = ex;
NoDisconnectRestartPlugin.Log.LogWarning((object)("[NDR] Catch-up pick invoke failed: " + ex2.Message));
}
}
}
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}