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 Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("QuickRestart")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+757791390981cd33951aaf2d51e0cfb4294c8a26")]
[assembly: AssemblyProduct("QuickRestart")]
[assembly: AssemblyTitle("QuickRestart")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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 QuickRestart
{
[BepInPlugin("com.ttr.quickrestart", "QuickRestart", "3.1.89")]
public class QuickRestartPlugin : BaseUnityPlugin
{
public const string PluginGuid = "com.ttr.quickrestart";
public const string PluginName = "QuickRestart";
public const string PluginVersion = "3.1.89";
internal static ManualLogSource Logger;
private const KeyCode CancelDayKey = (KeyCode)290;
private const string CancelDayBinding = "<Keyboard>/f9";
private const float RestartTimeoutSeconds = 90f;
private static QuickRestartPlugin _instance;
internal static bool _isCancelling;
private InputAction _cancelDayAction;
private InputAction _fastForwardAction;
private const string F8Binding = "<Keyboard>/f8";
private void Awake()
{
_instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
Harmony.CreateAndPatchAll(typeof(Patches), "com.ttr.quickrestart");
Logger.LogInfo((object)string.Format("{0} v{1} loaded! Press {2} or use the pause menu to restart the current run.", "QuickRestart", "3.1.89", (object)(KeyCode)290));
}
private void OnDestroy()
{
if (_cancelDayAction != null)
{
_cancelDayAction.performed -= OnCancelDayPerformed;
_cancelDayAction.Disable();
_cancelDayAction.Dispose();
_cancelDayAction = null;
}
}
private static void OnCancelDayPerformed(CallbackContext _)
{
CancelDay();
}
private static void OnF8Performed(CallbackContext _)
{
FastForwardToDeadline();
}
internal static void EnsureCancelDayActionReady()
{
_instance?.EnsureCancelDayAction();
}
private void EnsureCancelDayAction()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
if (_cancelDayAction != null)
{
return;
}
try
{
_cancelDayAction = new InputAction("QuickRestartCancelDay", (InputActionType)1, "<Keyboard>/f9", (string)null, (string)null, (string)null);
_cancelDayAction.performed += OnCancelDayPerformed;
_cancelDayAction.Enable();
Logger.LogInfo((object)"[QuickRestart] F9 restart binding ready.");
}
catch (Exception ex)
{
Logger.LogWarning((object)("[QuickRestart] F9 restart binding could not be initialized yet: " + ex.Message));
_cancelDayAction = null;
}
}
internal static void FastForwardToDeadline()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Invalid comparison between Unknown and I4
if (_isCancelling)
{
Logger.LogWarning((object)"[QuickRestart] F8 fast-forward blocked — cancellation in progress.");
return;
}
Bootstrap val = Object.FindObjectOfType<Bootstrap>();
if ((Object)(object)val == (Object)null || (int)val.State != 1)
{
Logger.LogInfo((object)"[QuickRestart] F8 fast-forward skipped — not in-game.");
return;
}
GameProgressionManager instance = GameProgressionManager.Instance;
if ((Object)(object)instance == (Object)null)
{
Logger.LogInfo((object)"[QuickRestart] F8 fast-forward skipped — no GameProgressionManager.");
return;
}
float num = instance.MaxSeconds - 60f;
SetNetworkVar(instance, "n_currentGameTime", Mathf.Max(0f, num));
Logger.LogInfo((object)$"[QuickRestart] Fast-forwarded: maxSeconds={instance.MaxSeconds}, set to t={num:F1} (~1 real min before deadline).");
}
internal static void CancelDay()
{
if (_isCancelling)
{
Logger.LogInfo((object)"[QuickRestart] Restart/cancel already in progress.");
return;
}
if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
{
Logger.LogInfo((object)"[QuickRestart] Only the host can cancel the day.");
return;
}
Bootstrap val = Object.FindObjectOfType<Bootstrap>();
if ((Object)(object)val == (Object)null)
{
Logger.LogInfo((object)"[QuickRestart] Bootstrap not found.");
return;
}
GameProgressionManager instance = GameProgressionManager.Instance;
if ((Object)(object)instance == (Object)null)
{
Logger.LogWarning((object)"[QuickRestart] GameProgressionManager not found.");
return;
}
_isCancelling = true;
RunCoroutine(RestartCurrentOrLastRun(val, instance));
}
private static IEnumerator RestartCurrentOrLastRun(Bootstrap bootstrap, GameProgressionManager progression)
{
try
{
Logger.LogInfo((object)$"[QuickRestart] Restart requested from {bootstrap.State} (transition: {IsInTransition()}).");
bool transitionInProgress = IsInTransition();
GameProgressionManager obj = progression;
bool flag = (Object)(object)((obj != null) ? obj.Deposit : null) != (Object)null && (progression.Deposit.PapyrusIsAnimating || progression.Deposit.PreventingRespawns);
if (!(transitionInProgress || flag) && !Patches.AnyPlayerDead())
{
Patches.HasLastGoodEquipment();
}
if ((int)bootstrap.State == 1)
{
Logger.LogInfo((object)$"[QuickRestart] Ending current run via owned instant transition (nativeTransition={transitionInProgress}, deadline={flag}, deadPlayers={Patches.AnyPlayerDead()}).");
Patches.PrepareForOwnedInstantRestart(bootstrap, progression);
if (!Patches.TryStartInstantLobbyTransition(bootstrap, (GameEndedReason)0, allowActiveTransition: true))
{
yield break;
}
}
else if ((int)bootstrap.State != 0 && !transitionInProgress)
{
Logger.LogInfo((object)$"[QuickRestart] Cannot restart from game state {bootstrap.State}.");
yield break;
}
yield return WaitForLobbyReady(bootstrap);
bootstrap = Object.FindObjectOfType<Bootstrap>();
progression = GameProgressionManager.Instance;
if ((Object)(object)bootstrap == (Object)null || (int)bootstrap.State != 0 || IsInTransition())
{
if (!transitionInProgress)
{
Logger.LogWarning((object)"[QuickRestart] Timed out waiting for lobby/post-loss state.");
yield break;
}
if (!IsInTransition() && (Object)(object)bootstrap != (Object)null && (int)bootstrap.State != 0)
{
Logger.LogInfo((object)"[QuickRestart] Native completed lobby but didn't set State; applying state.");
typeof(Bootstrap).GetField("gameState", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(bootstrap, (object)(GameState)0);
}
else
{
Logger.LogInfo((object)"[QuickRestart] Native transition timed out; falling back to forced transition.");
Patches.TryStartInstantLobbyTransition(bootstrap ?? Object.FindObjectOfType<Bootstrap>(), (GameEndedReason)0, allowActiveTransition: true);
yield return WaitForLobbyReady(bootstrap ?? Object.FindObjectOfType<Bootstrap>());
bootstrap = Object.FindObjectOfType<Bootstrap>();
progression = GameProgressionManager.Instance;
if ((Object)(object)bootstrap == (Object)null || (int)bootstrap.State != 0 || IsInTransition())
{
Logger.LogWarning((object)"[QuickRestart] Forced transition also failed.");
yield break;
}
}
}
Logger.LogInfo((object)"[QuickRestart] Lobby reached; cleaning up post-transition state then recovering.");
Patches.CancelActiveVortex(Patches.GetCurrentGnomeHouse());
Patches.StopTaskCallbacks();
if (Patches._depositWorldSaved)
{
GnomeHouse currentGnomeHouse = Patches.GetCurrentGnomeHouse();
if ((Object)(object)((currentGnomeHouse != null) ? currentGnomeHouse.GnomiumDeposit : null) != (Object)null)
{
try
{
Transform transform = ((Component)currentGnomeHouse.GnomiumDeposit).transform;
transform.position = Patches._savedDepositWorldPos;
transform.rotation = Patches._savedDepositWorldRot;
Logger.LogInfo((object)$"[QuickRestart] Restored deposit box (recovery path): worldPos={Patches._savedDepositWorldPos}");
}
catch (Exception ex)
{
Logger.LogWarning((object)("[QuickRestart] Failed to restore deposit box (recovery path): " + ex.Message));
}
}
}
if ((Object)(object)progression != (Object)null)
{
progression.SelectedLevelIndex = -1;
}
Patches.UseLastGoodEquipment();
ForceLobbyReady(progression);
ClearTaskListAndHints();
ResetPlayerControllerUiState();
yield return Patches.RecoverLobbyPlayersAndEquipment();
try
{
Type type = Type.GetType("ControllerSupport.ControllerSupportPlugin, ControllerSupport");
if (type != null)
{
type.GetMethod("OnGameRestarted", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null);
Logger.LogInfo((object)"[QuickRestart] Called ControllerSupport.OnGameRestarted.");
}
}
catch (Exception ex2)
{
Logger.LogWarning((object)("[QuickRestart] ControllerSupport.OnGameRestarted failed: " + ex2.Message));
}
Logger.LogInfo((object)"[QuickRestart] Restart recovery complete; staying in lobby.");
}
finally
{
FinishCancel();
}
}
private static IEnumerator WaitForLobbyReady(Bootstrap bootstrap, float timeoutSeconds = 90f)
{
float elapsed = 0f;
while ((Object)(object)bootstrap != (Object)null && ((int)bootstrap.State != 0 || IsInTransition()))
{
elapsed += Time.unscaledDeltaTime;
if (elapsed > timeoutSeconds)
{
break;
}
yield return null;
}
}
internal static void FinishCancel()
{
_isCancelling = false;
}
internal static void RunCoroutine(IEnumerator routine)
{
QuickRestartPlugin instance = _instance;
if (instance != null)
{
((MonoBehaviour)instance).StartCoroutine(routine);
}
}
internal static bool IsInTransition()
{
Bootstrap val = Object.FindObjectOfType<Bootstrap>();
if ((Object)(object)val == (Object)null)
{
return false;
}
FieldInfo field = typeof(Bootstrap).GetField("gameTransitionInProgress", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
{
return (bool)field.GetValue(val);
}
return false;
}
internal static T GetPrivate<T>(object obj, string fieldName)
{
FieldInfo field = obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
{
return default(T);
}
object value = field.GetValue(obj);
if (value is T)
{
return (T)value;
}
return default(T);
}
internal static bool IsUnityObjectAlive(object obj)
{
if (obj == null)
{
return false;
}
Object val = (Object)((obj is Object) ? obj : null);
if (val != null)
{
return val != (Object)null;
}
return true;
}
internal static void SetNetworkVar<T>(object obj, string fieldName, T value)
{
if (obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj) is NetworkVariable<T> val)
{
val.Value = value;
}
else
{
Logger.LogWarning((object)("[QuickRestart] Could not set " + fieldName + "."));
}
}
internal static void HideDeathOverlay()
{
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_instance == (Object)null)
{
return;
}
string[] array = new string[6] { "DeathOverlay", "DeathScreen", "GameOver", "GameOverScreen", "ContinuePanel", "ContinueScreen" };
foreach (string text in array)
{
try
{
GameObject val = GameObject.Find(text);
if ((Object)(object)val != (Object)null && val.activeInHierarchy)
{
Logger.LogInfo((object)("[QuickRestart] Found and hiding death overlay: " + text));
val.SetActive(false);
return;
}
}
catch
{
}
}
try
{
Canvas[] array2 = Object.FindObjectsOfType<Canvas>();
foreach (Canvas val2 in array2)
{
if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy)
{
continue;
}
Scene scene = ((Component)val2).gameObject.scene;
if (((Scene)(ref scene)).name == "DontDestroyOnLoad")
{
continue;
}
TMP_Text[] componentsInChildren = ((Component)val2).GetComponentsInChildren<TMP_Text>(true);
foreach (TMP_Text val3 in componentsInChildren)
{
if (!((Object)(object)val3 == (Object)null) && !string.IsNullOrEmpty(val3.text))
{
string text2 = val3.text.ToLowerInvariant();
if (text2.Contains("continue") || text2.Contains("game over") || text2.Contains("you died") || text2.Contains("death"))
{
Logger.LogInfo((object)("[QuickRestart] Hiding death overlay (found text: '" + val3.text + "')"));
((Component)val2).gameObject.SetActive(false);
return;
}
}
}
}
}
catch
{
}
Logger.LogInfo((object)"[QuickRestart] Could not find death overlay to hide.");
}
internal static void ClickContinueButton()
{
try
{
Button[] array = Object.FindObjectsOfType<Button>(true);
foreach (Button val in array)
{
if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy && ((Selectable)val).interactable)
{
TMP_Text componentInChildren = ((Component)val).GetComponentInChildren<TMP_Text>(true);
if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.ToLowerInvariant().Contains("continue"))
{
Logger.LogInfo((object)("[QuickRestart] Clicking Continue button (text: '" + componentInChildren.text + "')."));
((UnityEvent)val.onClick).Invoke();
return;
}
}
}
Logger.LogInfo((object)"[QuickRestart] Could not find Continue button.");
}
catch (Exception ex)
{
Logger.LogWarning((object)("[QuickRestart] Exception finding Continue button: " + ex.Message));
}
}
internal static void ClearTaskListAndHints()
{
//IL_0537: Unknown result type (might be due to invalid IL or missing references)
//IL_0578: Unknown result type (might be due to invalid IL or missing references)
try
{
PlayerController[] array = Object.FindObjectsOfType<PlayerController>(false);
Logger.LogInfo((object)$"[QuickRestart] Found {array.Length} PlayerController(s) in lobby.");
PlayerController[] array2 = array;
foreach (PlayerController val in array2)
{
if ((Object)(object)val == (Object)null)
{
Logger.LogInfo((object)"[QuickRestart] PlayerController is null (Unity-destroyed).");
continue;
}
ManualLogSource logger = Logger;
GameObject gameObject = ((Component)val).gameObject;
logger.LogInfo((object)string.Format("[QuickRestart] Player: {0} active={1}", ((gameObject != null) ? ((Object)gameObject).name : null) ?? "(no GO)", ((Behaviour)val).isActiveAndEnabled));
FieldInfo field = typeof(PlayerController).GetField("taskPanel", BindingFlags.Instance | BindingFlags.NonPublic);
object obj = field?.GetValue(val);
Logger.LogInfo((object)string.Format("[QuickRestart] taskPanel field found={0}, value={1}", field != null, obj?.GetType().Name ?? "null"));
GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
if (val2 != null)
{
val2.SetActive(false);
Logger.LogInfo((object)$"[QuickRestart] Disabled task panel \"{((Object)val2).name}\" activeBefore={val2.activeSelf}.");
}
FieldInfo field2 = typeof(PlayerController).GetField("DescriptionDisplayer", BindingFlags.Instance | BindingFlags.NonPublic);
object obj2 = field2?.GetValue(val);
Logger.LogInfo((object)string.Format("[QuickRestart] DescriptionDisplayer field found={0}, value={1}", field2 != null, obj2?.GetType().Name ?? "null"));
DescriptionDisplayer val3 = (DescriptionDisplayer)((obj2 is DescriptionDisplayer) ? obj2 : null);
if (val3 != null)
{
val3.DisableTaskList();
val3.ClearTaskList();
Logger.LogInfo((object)"[QuickRestart] Called DisableTaskList and ClearTaskList.");
}
}
GameProgressionManager instance = GameProgressionManager.Instance;
if (!((Object)(object)instance != (Object)null))
{
return;
}
if (typeof(GameProgressionManager).GetField("onGameEnded", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance) is Delegate obj3)
{
Delegate[] invocationList = obj3.GetInvocationList();
foreach (Delegate obj4 in invocationList)
{
Logger.LogInfo((object)("[QuickRestart] onGameEnded subscriber: " + obj4.Target?.GetType().FullName + "." + obj4.Method?.Name));
}
Dictionary<int, bool> dictionary = new Dictionary<int, bool>();
Canvas[] array3 = Object.FindObjectsOfType<Canvas>(false);
foreach (Canvas val4 in array3)
{
if ((Object)(object)val4 != (Object)null)
{
dictionary[((Object)val4).GetInstanceID()] = ((Behaviour)val4).isActiveAndEnabled;
}
}
object obj5 = typeof(GameProgressionManager).GetField("n_day", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance);
PropertyInfo propertyInfo = obj5?.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public);
int num = 0;
if (obj5 != null && propertyInfo != null)
{
num = (int)(propertyInfo.GetValue(obj5) ?? ((object)0));
}
Logger.LogInfo((object)"[QuickRestart] Firing onGameEnded event manually as PLAYER_ACTION.");
obj3.DynamicInvoke((object)(GameEndedReason)0);
if (obj5 != null && propertyInfo != null)
{
int num2 = (int)propertyInfo.GetValue(obj5);
if (num2 != num)
{
propertyInfo.SetValue(obj5, num);
Logger.LogInfo((object)$"[QuickRestart] Restored day counter from {num2} to {num}.");
}
}
object obj6 = typeof(GameProgressionManager).GetField("n_currentGameTime", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(instance);
PropertyInfo propertyInfo2 = obj6?.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public);
if (obj6 != null && propertyInfo2 != null)
{
float num3 = (float)propertyInfo2.GetValue(obj6);
if (num3 > 5f)
{
propertyInfo2.SetValue(obj6, 0f);
Logger.LogInfo((object)$"[QuickRestart] Reset game time from {num3:F1}s to 0s.");
}
}
array3 = Object.FindObjectsOfType<Canvas>(false);
foreach (Canvas val5 in array3)
{
if (!((Object)(object)val5 == (Object)null))
{
int instanceID = ((Object)val5).GetInstanceID();
bool value;
bool flag = dictionary.TryGetValue(instanceID, out value);
bool isActiveAndEnabled = ((Behaviour)val5).isActiveAndEnabled;
if (!flag && isActiveAndEnabled)
{
Logger.LogInfo((object)$"[QuickRestart] NEW active Canvas after event: \"{((Object)val5).name}\" order={val5.sortingOrder} — disabling.");
((Component)val5).gameObject.SetActive(false);
}
else if (flag && !value && isActiveAndEnabled)
{
Logger.LogInfo((object)$"[QuickRestart] ACTIVATED Canvas after event: \"{((Object)val5).name}\" order={val5.sortingOrder} — disabling.");
((Component)val5).gameObject.SetActive(false);
}
}
}
Type type = Type.GetType("UnityEngine.UIElements.UIDocument, UnityEngine.UIElements, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
if (!(type != null))
{
return;
}
HashSet<int> hashSet = new HashSet<int>();
Object[] array4 = Resources.FindObjectsOfTypeAll(type);
for (int i = 0; i < array4.Length; i++)
{
GameObject gameObject2 = ((Component)array4[i]).gameObject;
if ((Object)(object)gameObject2 != (Object)null)
{
hashSet.Add(((Object)gameObject2).GetInstanceID());
}
}
array4 = Resources.FindObjectsOfTypeAll(type);
for (int i = 0; i < array4.Length; i++)
{
GameObject gameObject3 = ((Component)array4[i]).gameObject;
if (!((Object)(object)gameObject3 == (Object)null) && gameObject3.activeInHierarchy && !hashSet.Contains(((Object)gameObject3).GetInstanceID()))
{
Logger.LogInfo((object)("[QuickRestart] NEW active UIDocument after event: \"" + ((Object)gameObject3).name + "\" — disabling."));
gameObject3.SetActive(false);
}
}
}
else
{
Logger.LogInfo((object)"[QuickRestart] Could not access onGameEnded event backing field (no subscribers?).");
}
}
catch (Exception ex)
{
Logger.LogWarning((object)("[QuickRestart] ClearTaskListAndHints exception: " + ex.Message));
}
}
internal static IEnumerator DelayedLobbyReinitialize(Bootstrap bootstrap)
{
yield return null;
if ((Object)(object)bootstrap == (Object)null)
{
yield break;
}
LobbyManager component = ((Component)bootstrap).GetComponent<LobbyManager>();
string[] array;
if ((Object)(object)component != (Object)null)
{
array = new string[5] { "OnEnteredLobby", "OnLobbyReady", "OnLobbyEntered", "Initialize", "SetupLobby" };
foreach (string text in array)
{
try
{
MethodInfo method = typeof(LobbyManager).GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method != null && method.GetParameters().Length == 0)
{
Logger.LogInfo((object)("[QuickRestart] Calling LobbyManager." + text + "()"));
method.Invoke(component, null);
}
}
catch
{
}
}
}
array = new string[6] { "Well", "WellOfCreation", "Bell", "TownBell", "Stockpile", "TownStockpile" };
foreach (string text2 in array)
{
try
{
GameObject val = GameObject.Find(text2);
if ((Object)(object)val != (Object)null && val.activeInHierarchy)
{
Logger.LogInfo((object)("[QuickRestart] Force-reinitializing lobby object: " + text2));
val.SetActive(false);
val.SetActive(true);
}
}
catch
{
}
}
}
internal static void ForceLobbyReady(GameProgressionManager progression)
{
if ((Object)(object)progression == (Object)null)
{
return;
}
try
{
Type type = ((object)progression).GetType();
FieldInfo field = type.GetField("n_timeActive", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
{
object value = field.GetValue(progression);
PropertyInfo propertyInfo = value?.GetType().GetProperty("Value");
if (propertyInfo != null && propertyInfo.PropertyType == typeof(bool))
{
propertyInfo.SetValue(value, false);
}
}
FieldInfo field2 = type.GetField("n_gameState", BindingFlags.Instance | BindingFlags.NonPublic);
if (field2 != null)
{
object value2 = field2.GetValue(progression);
PropertyInfo propertyInfo2 = value2?.GetType().GetProperty("Value");
if (propertyInfo2 != null && propertyInfo2.PropertyType.IsEnum)
{
object value3 = Enum.ToObject(propertyInfo2.PropertyType, 0);
propertyInfo2.SetValue(value2, value3);
}
}
GnomiumDeposit deposit = progression.Deposit;
if ((Object)(object)deposit != (Object)null)
{
Type type2 = ((object)deposit).GetType();
FieldInfo field3 = type2.GetField("preventRespawning", BindingFlags.Instance | BindingFlags.NonPublic);
if (field3 != null && field3.FieldType == typeof(bool))
{
field3.SetValue(deposit, false);
}
FieldInfo field4 = type2.GetField("papyrusInProgress", BindingFlags.Instance | BindingFlags.NonPublic);
if (field4 != null && field4.FieldType == typeof(bool))
{
field4.SetValue(deposit, false);
}
}
}
catch (Exception ex)
{
Logger.LogWarning((object)("[QuickRestart] ForceLobbyReady exception: " + ex.Message));
}
ResetPlayerControllerUiState();
HideGameOverScreen();
Logger.LogInfo((object)"[QuickRestart] Lobby state forced to interactive.");
}
internal static void HideGameOverScreen()
{
try
{
GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
foreach (GameObject val in array)
{
if (val.activeInHierarchy)
{
string name = ((Object)val).name;
if (name.IndexOf("GameOver", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("DeadCanvas", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("GameOverlay", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("EndGame", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Recap", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("text_gameover", StringComparison.OrdinalIgnoreCase) >= 0)
{
val.SetActive(false);
Logger.LogInfo((object)("[QuickRestart] Hid screen: " + ((Object)val).name));
}
}
}
}
catch (Exception ex)
{
Logger.LogWarning((object)("[QuickRestart] HideGameOverScreen exception: " + ex.Message));
}
}
internal static void ResetPlayerControllerUiState()
{
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Expected O, but got Unknown
//IL_0514: Unknown result type (might be due to invalid IL or missing references)
//IL_051b: Expected O, but got Unknown
int num = 0;
PlayerController[] array = Object.FindObjectsOfType<PlayerController>();
foreach (PlayerController val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
bool flag = false;
FieldInfo field = ((object)val).GetType().GetField("isUiOpen", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null && field.FieldType == typeof(bool) && (bool)(field.GetValue(val) ?? ((object)false)))
{
field.SetValue(val, false);
flag = true;
}
FieldInfo field2 = ((object)val).GetType().GetField("isInventoryOpen", BindingFlags.Instance | BindingFlags.NonPublic);
if (field2 != null && field2.FieldType == typeof(bool) && (bool)(field2.GetValue(val) ?? ((object)false)))
{
field2.SetValue(val, false);
flag = true;
}
object? obj = ((object)val).GetType().GetField("ingameMenu", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val);
GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
if (val2 != null && val2.activeSelf)
{
foreach (Transform item in val2.transform)
{
Transform val3 = item;
if (!((Component)val3).gameObject.activeSelf)
{
((Component)val3).gameObject.SetActive(true);
}
}
val2.SetActive(false);
flag = true;
}
FieldInfo? field3 = ((object)val).GetType().GetField("settingsPanel", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field4 = ((object)val).GetType().GetField("settingsButtons", BindingFlags.Instance | BindingFlags.NonPublic);
object? obj2 = field3?.GetValue(val);
GameObject val4 = (GameObject)((obj2 is GameObject) ? obj2 : null);
if (val4 != null && val4.activeSelf)
{
val4.SetActive(false);
flag = true;
}
object? obj3 = field4?.GetValue(val);
GameObject val5 = (GameObject)((obj3 is GameObject) ? obj3 : null);
if (val5 != null && !val5.activeSelf)
{
val5.SetActive(true);
flag = true;
}
FieldInfo field5 = ((object)val).GetType().GetField("settingsPanelMode", BindingFlags.Instance | BindingFlags.NonPublic);
if (field5 != null)
{
field5.SetValue(val, 1);
}
FieldInfo? field6 = ((object)val).GetType().GetField("ingameMenu", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field7 = ((object)val).GetType().GetField("settingsButtons", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field8 = ((object)val).GetType().GetField("settingsPanel", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field9 = ((object)val).GetType().GetField("rebindPanel", BindingFlags.Instance | BindingFlags.NonPublic);
object? obj4 = field6?.GetValue(val);
GameObject go = (GameObject)((obj4 is GameObject) ? obj4 : null);
object? obj5 = field7?.GetValue(val);
GameObject go2 = (GameObject)((obj5 is GameObject) ? obj5 : null);
object? obj6 = field8?.GetValue(val);
GameObject go3 = (GameObject)((obj6 is GameObject) ? obj6 : null);
object? obj7 = field9?.GetValue(val);
GameObject go4 = (GameObject)((obj7 is GameObject) ? obj7 : null);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("[QuickRestart] UI diag: isUiOpen=" + (field?.GetValue(val) ?? "null")?.ToString() + ", isInventoryOpen=" + (field2?.GetValue(val) ?? "null")?.ToString() + "\n");
LogUiGameObject(stringBuilder, "ingameMenu", go);
LogUiGameObject(stringBuilder, "settingsButtons", go2);
LogUiGameObject(stringBuilder, "settingsPanel", go3);
LogUiGameObject(stringBuilder, "rebindPanel", go4);
Logger.LogInfo((object)stringBuilder.ToString());
object? obj8 = ((object)val).GetType().GetField("ingameMenu", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val);
GameObject val6 = (GameObject)((obj8 is GameObject) ? obj8 : null);
if (val6 != null && (Object)(object)val6 != (Object)null)
{
Transform parent = val6.transform.parent;
if ((Object)(object)parent != (Object)null)
{
GameObject gameObject = ((Component)parent).gameObject;
if ((Object)(object)gameObject != (Object)null)
{
Canvas val7 = gameObject.GetComponent<Canvas>();
if ((Object)(object)val7 == (Object)null)
{
val7 = gameObject.AddComponent<Canvas>();
val7.renderMode = (RenderMode)0;
Logger.LogInfo((object)("[QuickRestart] Added Canvas to '" + ((Object)gameObject).name + "'."));
flag = true;
}
if (!((Behaviour)val7).enabled)
{
((Behaviour)val7).enabled = true;
Logger.LogInfo((object)("[QuickRestart] Re-enabled Canvas on '" + ((Object)gameObject).name + "'."));
flag = true;
}
if (!gameObject.activeSelf)
{
gameObject.SetActive(true);
Logger.LogInfo((object)("[QuickRestart] Activated '" + ((Object)gameObject).name + "' (was inactive)."));
flag = true;
}
Transform parent2 = gameObject.transform.parent;
while ((Object)(object)parent2 != (Object)null)
{
if (!((Component)parent2).gameObject.activeSelf)
{
((Component)parent2).gameObject.SetActive(true);
Logger.LogInfo((object)("[QuickRestart] Activated ancestor '" + ((Object)parent2).name + "'."));
flag = true;
}
parent2 = parent2.parent;
}
}
}
else
{
GameObject val8 = new GameObject("Canvas in front");
val8.transform.SetParent(((Component)val).transform, false);
val8.AddComponent<Canvas>().renderMode = (RenderMode)0;
val6.transform.SetParent(val8.transform, false);
Logger.LogInfo((object)"[QuickRestart] Created new 'Canvas in front' under PC, reparented menu.");
flag = true;
}
}
object obj9 = ((object)val).GetType().GetField("frontCanvas", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val);
if (obj9 != null)
{
GameObject val9 = (GameObject)((obj9 is GameObject) ? obj9 : null);
if ((Object)(object)val9 != (Object)null && (Object)(object)val9.GetComponent<Canvas>() == (Object)null)
{
val9.AddComponent<Canvas>().renderMode = (RenderMode)0;
Logger.LogInfo((object)"[QuickRestart] Added Canvas to frontCanvas fallback.");
flag = true;
}
}
if (flag)
{
num++;
}
}
if (num > 0)
{
Logger.LogInfo((object)$"[QuickRestart] Reset UI state on {num} PlayerControllers (including ingameMenu).");
}
}
private static void LogUiGameObject(StringBuilder sb, string label, GameObject go)
{
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
//IL_02de: Expected O, but got Unknown
if ((Object)(object)go == (Object)null)
{
sb.Append(" " + label + ": NULL (destroyed or unassigned)\n");
return;
}
Canvas componentInParent = go.GetComponentInParent<Canvas>();
Canvas component = go.GetComponent<Canvas>();
CanvasGroup component2 = go.GetComponent<CanvasGroup>();
string text = (((Object)(object)component2 != (Object)null) ? component2.alpha.ToString("F2") : "N/A");
string text2 = (((Object)(object)component2 != (Object)null) ? component2.blocksRaycasts.ToString() : "N/A");
sb.Append(" " + label + ": activeSelf=" + go.activeSelf + ", activeInHierarchy=" + go.activeInHierarchy + "\n");
sb.Append(" parent=" + (((Object)(object)go.transform.parent != (Object)null) ? ((Object)go.transform.parent).name : "null") + "\n");
sb.Append(" hasCanvasAncestor=" + (((Object)(object)componentInParent != (Object)null) ? "true" : "false") + ", hasCanvasSelf=" + (((Object)(object)component != (Object)null) ? "true" : "false") + "\n");
if ((Object)(object)componentInParent != (Object)null)
{
sb.Append(" canvas: renderMode=" + ((object)componentInParent.renderMode/*cast due to .constrained prefix*/).ToString() + ", worldCamera=" + (((Object)(object)componentInParent.worldCamera != (Object)null) ? ((Object)componentInParent.worldCamera).name : "null") + ", sortingOrder=" + componentInParent.sortingOrder + ", enabled=" + ((Behaviour)componentInParent).enabled + "\n");
}
sb.Append(" canvasGroup: alpha=" + text + ", blocksRaycasts=" + text2 + "\n");
sb.Append(" hierarchyDepth=" + go.transform.hierarchyCount + ", childCount=" + go.transform.childCount + "\n");
if (go.transform.childCount <= 0)
{
return;
}
sb.Append(" children:\n");
foreach (Transform item in go.transform)
{
Transform val = item;
sb.Append(" [" + val.GetSiblingIndex() + "] " + ((Object)val).name + ": activeSelf=" + ((Component)val).gameObject.activeSelf + ", activeInHierarchy=" + ((Component)val).gameObject.activeInHierarchy + "\n");
}
}
internal static bool SetBoolField(object obj, string fieldName, bool value)
{
try
{
FieldInfo field = obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null && field.FieldType == typeof(bool))
{
field.SetValue(obj, value);
return true;
}
}
catch
{
}
return false;
}
private static Transform FindChildTransform(Transform parent, string name)
{
if ((Object)(object)parent == (Object)null)
{
return null;
}
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if (((Object)child).name == name)
{
return child;
}
Transform val = FindChildTransform(child, name);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
return null;
}
internal static void ClearBlockingFlag(object obj, string name)
{
try
{
Type type = obj.GetType();
FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
if (field.FieldType == typeof(bool))
{
field.SetValue(obj, false);
return;
}
PropertyInfo property = field.FieldType.GetProperty("Value", typeof(bool));
if (property != null)
{
object value = field.GetValue(obj);
property.SetValue(value, false);
return;
}
}
PropertyInfo property2 = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property2 != null && property2.CanWrite && property2.PropertyType == typeof(bool))
{
property2.SetValue(obj, false);
return;
}
FieldInfo field2 = type.GetField("<" + name + ">k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
if (field2 != null && field2.FieldType == typeof(bool))
{
field2.SetValue(obj, false);
return;
}
string[] array = new string[4]
{
"m_" + name,
"_" + name,
"net" + name,
"_net" + name
};
foreach (string name2 in array)
{
FieldInfo field3 = type.GetField(name2, BindingFlags.Instance | BindingFlags.NonPublic);
if (field3 != null)
{
if (field3.FieldType == typeof(bool))
{
field3.SetValue(obj, false);
break;
}
PropertyInfo property3 = field3.FieldType.GetProperty("Value", typeof(bool));
if (property3 != null)
{
object value2 = field3.GetValue(obj);
property3.SetValue(value2, false);
break;
}
}
}
}
catch
{
}
}
}
public static class Patches
{
private sealed class EquipmentSnapshot
{
public ulong NetworkObjectId;
public ulong OwnerClientId;
public List<InventoryItem> Items = new List<InventoryItem>();
}
[CompilerGenerated]
private static class <>O
{
public static UnityAction <0>__CancelDay;
}
public static bool SkipVortex;
internal static bool _depositWorldSaved = false;
internal static Vector3 _savedDepositWorldPos;
internal static Quaternion _savedDepositWorldRot;
private static readonly List<EquipmentSnapshot> EquipmentSnapshots = new List<EquipmentSnapshot>();
private static readonly List<EquipmentSnapshot> LastGoodEquipment = new List<EquipmentSnapshot>();
private static readonly HashSet<ulong> _phase1CompletePlayers = new HashSet<ulong>();
private static GameObject _lastSettingsButtons;
private static Button _restartButton;
internal static void UseLastGoodEquipment()
{
if (LastGoodEquipment.Count == 0)
{
QuickRestartPlugin.Logger.LogWarning((object)"[QuickRestart] No bell-time equipment snapshot available to restore.");
return;
}
EquipmentSnapshots.Clear();
int num = 0;
foreach (EquipmentSnapshot item in LastGoodEquipment)
{
if (item.Items.Count != 0)
{
EquipmentSnapshot equipmentSnapshot = new EquipmentSnapshot
{
NetworkObjectId = item.NetworkObjectId,
OwnerClientId = item.OwnerClientId
};
equipmentSnapshot.Items.AddRange(item.Items);
EquipmentSnapshots.Add(equipmentSnapshot);
num += item.Items.Count;
}
}
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Loaded bell-time equipment snapshot: {EquipmentSnapshots.Count} players ({num} items).");
}
[HarmonyPatch(typeof(PlayerNetworking), "DisplayGameOverScreenRpc")]
[HarmonyPrefix]
public static bool DisplayGameOverRpcPrefix()
{
if (QuickRestartPlugin._isCancelling)
{
return false;
}
return true;
}
[HarmonyPatch(typeof(PlayerController), "Start")]
[HarmonyPostfix]
public static void PlayerControllerStartPostfix(PlayerController __instance)
{
QuickRestartPlugin.EnsureCancelDayActionReady();
TryInjectRestartButton(__instance);
}
[HarmonyPatch(typeof(InputSystemHandler), "Awake")]
[HarmonyPostfix]
public static void InputSystemHandlerAwakePostfix()
{
QuickRestartPlugin.EnsureCancelDayActionReady();
}
[HarmonyPatch(typeof(PlayerController), "OnDied")]
[HarmonyPostfix]
public static void PlayerControllerOnDiedPostfix(PlayerController __instance)
{
TryInjectRestartButton(__instance);
}
[HarmonyPatch(typeof(PlayerController), "OnRespawned")]
[HarmonyPostfix]
public static void PlayerControllerOnRespawnedPostfix(PlayerController __instance)
{
TryInjectRestartButton(__instance);
}
[HarmonyPatch(typeof(PlayerController), "OnTied")]
[HarmonyPostfix]
public static void PlayerControllerOnTiedPostfix(PlayerController __instance)
{
TryInjectRestartButton(__instance);
}
[HarmonyPatch(typeof(PlayerController), "OnUnTied")]
[HarmonyPostfix]
public static void PlayerControllerOnUnTiedPostfix(PlayerController __instance)
{
TryInjectRestartButton(__instance);
}
[HarmonyPatch(typeof(PlayerController), "DisplayGameOver")]
[HarmonyPostfix]
public static void PlayerControllerDisplayGameOverPostfix(PlayerController __instance)
{
TryInjectRestartButton(__instance);
}
[HarmonyPatch(typeof(GameProgressionManager), "OnGameStarted")]
[HarmonyPostfix]
public static void OnGameStartedPostfix()
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
ResetMenuInjection();
EnsureRestartButtonOnLocalPlayer();
QuickRestartPlugin.RunCoroutine(DelayedLastGoodEquipmentCapture());
if (_depositWorldSaved)
{
return;
}
try
{
GnomeHouse val = Object.FindObjectOfType<GnomeHouse>();
if ((Object)(object)((val != null) ? val.GnomiumDeposit : null) != (Object)null)
{
Transform transform = ((Component)val.GnomiumDeposit).transform;
_savedDepositWorldPos = transform.position;
_savedDepositWorldRot = transform.rotation;
_depositWorldSaved = true;
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Saved deposit box: worldPos={_savedDepositWorldPos} worldRot={((Quaternion)(ref _savedDepositWorldRot)).eulerAngles}");
}
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Failed to save deposit box: " + ex.Message));
}
}
private static IEnumerator DelayedLastGoodEquipmentCapture()
{
yield return null;
CaptureLastGoodEquipment();
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Game-start snapshot: {LastGoodEquipment.Count} players with items.");
}
internal static void CaptureLastGoodEquipment()
{
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
LastGoodEquipment.Clear();
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
foreach (PlayerNetworking val in array)
{
if ((Object)(object)val == (Object)null || (Object)(object)val.Inventory == (Object)null || (Object)(object)((NetworkBehaviour)val).NetworkObject == (Object)null)
{
continue;
}
EquipmentSnapshot equipmentSnapshot = new EquipmentSnapshot
{
NetworkObjectId = ((NetworkBehaviour)val).NetworkObjectId,
OwnerClientId = ((NetworkBehaviour)val).OwnerClientId
};
foreach (InventoryItem content in ((InventoryBase)val.Inventory).Contents)
{
InventoryItem current = content;
if (((InventoryItem)(ref current)).IsValidItem)
{
equipmentSnapshot.Items.Add(current);
}
}
if (equipmentSnapshot.Items.Count > 0)
{
LastGoodEquipment.Add(equipmentSnapshot);
}
List<string> list = new List<string>();
foreach (InventoryItem item in equipmentSnapshot.Items)
{
InventoryItem current2 = item;
list.Add($"[slot:{current2.slotIndex} item:{((InventoryItem)(ref current2)).ItemIndex}]");
}
QuickRestartPlugin.Logger.LogInfo((object)string.Format("[QuickRestart] Player {0} snapshot: {1} items — {2}", ((NetworkBehaviour)val).OwnerClientId, equipmentSnapshot.Items.Count, string.Join(", ", list)));
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Player {((NetworkBehaviour)val).OwnerClientId} slotCount={((InventoryBase)val.Inventory).SlotCount}");
}
}
[HarmonyPatch(typeof(GameProgressionManager), "ResetGame")]
[HarmonyPrefix]
public static bool ResetGamePrefix()
{
if (QuickRestartPlugin._isCancelling)
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Suppressed ResetGame (day/save) during restart.");
return false;
}
return true;
}
[HarmonyPatch(typeof(GameProgressionManager), "OnGameEnded")]
[HarmonyPrefix]
public static bool OnGameEndedPrefix(GameProgressionManager __instance)
{
if (QuickRestartPlugin._isCancelling)
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Suppressed OnGameEnded during restart.");
try
{
if (typeof(GameProgressionManager).GetField("onGameEnded", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) is Delegate obj)
{
Delegate[] invocationList = obj.GetInvocationList();
foreach (Delegate obj2 in invocationList)
{
QuickRestartPlugin.Logger.LogInfo((object)("[QuickRestart] onGameEnded subscriber: " + obj2.Target?.GetType().FullName + "." + obj2.Method?.Name));
}
}
}
catch
{
}
return false;
}
return true;
}
[HarmonyPatch(typeof(GnomeHouse), "OnNetworkSpawn")]
[HarmonyPostfix]
public static void GnomeHouseSpawned()
{
_depositWorldSaved = false;
}
[HarmonyPatch(typeof(Bootstrap), "GoToLobby")]
[HarmonyPrefix]
public static bool GoToLobbyPrefix(Bootstrap __instance, GameEndedReason reason)
{
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
if (QuickRestartPlugin._isCancelling)
{
QuickRestartPlugin._isCancelling = false;
QuickRestartPlugin.Logger.LogWarning((object)"[QuickRestart] Cleared stuck _isCancelling in GoToLobbyPrefix.");
}
if (!_depositWorldSaved)
{
try
{
GnomeHouse val = Object.FindObjectOfType<GnomeHouse>();
if ((Object)(object)((val != null) ? val.GnomiumDeposit : null) != (Object)null)
{
Transform transform = ((Component)val.GnomiumDeposit).transform;
_savedDepositWorldPos = transform.position;
_savedDepositWorldRot = transform.rotation;
_depositWorldSaved = true;
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] GoToLobby fallback save: deposit worldPos={_savedDepositWorldPos} rot={((Quaternion)(ref _savedDepositWorldRot)).eulerAngles}");
}
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] GoToLobby fallback save failed: " + ex.Message));
}
}
if (!SkipVortex)
{
return true;
}
SkipVortex = false;
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Instant lobby transition.");
TryStartInstantLobbyTransition(__instance, reason, allowActiveTransition: false);
return false;
}
internal static bool TryStartInstantLobbyTransition(Bootstrap bootstrap, GameEndedReason reason, bool allowActiveTransition, bool skipHomeAssembly = false)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)bootstrap == (Object)null)
{
return false;
}
Type? typeFromHandle = typeof(Bootstrap);
FieldInfo field = typeFromHandle.GetField("gameTransitionInProgress", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field2 = typeFromHandle.GetField("gameState", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field3 = typeFromHandle.GetField("isOnlineMode", BindingFlags.Instance | BindingFlags.NonPublic);
FieldInfo field4 = typeFromHandle.GetField("gnomeHouse", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null && (bool)field.GetValue(bootstrap))
{
if (!allowActiveTransition)
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Transition already in progress.");
return false;
}
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Cancelling Bootstrap transition coroutine so QuickRestart can complete the restart.");
((MonoBehaviour)bootstrap).StopAllCoroutines();
}
if ((int)bootstrap.State == 0)
{
QuickRestartPlugin.Logger.LogWarning((object)"[QuickRestart] Already in lobby.");
return false;
}
object? obj = field4?.GetValue(bootstrap);
GnomeHouse val = (GnomeHouse)((obj is GnomeHouse) ? obj : null);
HomeManager val2 = null;
if (!skipHomeAssembly && (Object)(object)val != (Object)null)
{
object? obj2 = typeof(GnomeHouse).GetProperty("PlayerHome")?.GetValue(val);
val2 = (HomeManager)(((obj2 is HomeManager) ? obj2 : null) ?? ((Component)val).GetComponentInChildren<HomeManager>());
}
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] gnomeHouse: {(Object)(object)val != (Object)null}, homeManager: {(Object)(object)val2 != (Object)null}");
QuickRestartPlugin.RunCoroutine(InstantTransition(bootstrap, field, field2, field3, val, val2, reason));
return true;
}
internal static void PrepareForOwnedInstantRestart(Bootstrap bootstrap, GameProgressionManager progression)
{
try
{
QuickRestartPlugin.HideDeathOverlay();
QuickRestartPlugin.HideGameOverScreen();
StopTaskCallbacks();
if ((Object)(object)((progression != null) ? progression.Deposit : null) != (Object)null)
{
GnomiumDeposit deposit = progression.Deposit;
((MonoBehaviour)deposit).StopAllCoroutines();
Type type = ((object)deposit).GetType();
type.GetField("papyrusInProgress", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(deposit, false);
type.GetField("preventRespawning", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(deposit, false);
type.GetMethod("ResetPapyrus", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(deposit, null);
CancelActiveVortex(deposit.House);
}
ResetPlayersForOwnedRestart();
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Owned instant pre-cleanup failed (non-fatal): " + ex.Message));
}
}
private static void ResetPlayersForOwnedRestart()
{
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
foreach (PlayerNetworking val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
try
{
((MonoBehaviour)val).StopAllCoroutines();
RestorePlayerFromVortexState(val);
AccessTools.Field(typeof(PlayerNetworking), "respawning")?.SetValue(val, false);
AccessTools.Field(typeof(PlayerNetworking), "keepAtRespawnPos")?.SetValue(val, false);
if ((Object)(object)val.Dismemberment != (Object)null)
{
val.Dismemberment.ResetAllRpc();
}
if ((Object)(object)val.Health != (Object)null && ((HealthBase)val.Health).Dead)
{
((HealthBase)val.Health).Respawn();
}
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)$"[QuickRestart] Player restart cleanup failed for {((NetworkBehaviour)val).NetworkObjectId} (non-fatal): {ex.Message}");
}
}
}
internal static void EnsureRestartButtonOnLocalPlayer()
{
PlayerController val = ResolveLocalPlayerController();
if ((Object)(object)val != (Object)null)
{
TryInjectRestartButton(val);
}
}
private static void TryInjectRestartButton(PlayerController controller)
{
if ((Object)(object)controller == (Object)null || !IsLocalPlayerController(controller))
{
return;
}
GameObject val = QuickRestartPlugin.GetPrivate<GameObject>(controller, "settingsButtons");
if ((Object)(object)val == (Object)null)
{
return;
}
if ((Object)(object)_lastSettingsButtons != (Object)(object)val || (Object)(object)_restartButton == (Object)null || (Object)(object)((Component)_restartButton).gameObject == (Object)null)
{
ResetMenuInjection();
}
if ((Object)(object)_restartButton != (Object)null)
{
return;
}
Button val2 = FindExistingRestartButton(val);
if ((Object)(object)val2 != (Object)null)
{
_restartButton = val2;
PrepareRestartButton(((Component)_restartButton).gameObject);
_lastSettingsButtons = val;
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Adopted existing RESTART button in pause menu.");
return;
}
Button val3 = FindTemplateButton(val);
if (!((Object)(object)val3 == (Object)null))
{
GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, ((Component)val3).transform.parent);
((Object)val4).name = "QuickRestartButton";
val4.transform.SetSiblingIndex(Mathf.Min(1, val4.transform.parent.childCount - 1));
_restartButton = val4.GetComponent<Button>();
if ((Object)(object)_restartButton == (Object)null)
{
Object.Destroy((Object)(object)val4);
return;
}
PrepareRestartButton(val4);
_lastSettingsButtons = val;
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Injected RESTART button into pause menu.");
}
}
private static PlayerController ResolveLocalPlayerController()
{
try
{
PlayerNetworking localPlayer = ServerManager.GetLocalPlayer();
if (QuickRestartPlugin.IsUnityObjectAlive(localPlayer) && QuickRestartPlugin.IsUnityObjectAlive(localPlayer.Controller))
{
return localPlayer.Controller;
}
}
catch
{
}
PlayerController[] array = Object.FindObjectsOfType<PlayerController>();
foreach (PlayerController val in array)
{
if (IsLocalPlayerController(val))
{
return val;
}
}
return null;
}
private static bool IsLocalPlayerController(PlayerController controller)
{
if (!QuickRestartPlugin.IsUnityObjectAlive(controller))
{
return false;
}
try
{
PlayerNetworking val = QuickRestartPlugin.GetPrivate<PlayerNetworking>(controller, "networking");
return QuickRestartPlugin.IsUnityObjectAlive(val) && ((NetworkBehaviour)val).IsLocalPlayer;
}
catch
{
return false;
}
}
private static Button FindTemplateButton(GameObject settingsButtons)
{
Button[] componentsInChildren = settingsButtons.GetComponentsInChildren<Button>(true);
foreach (Button val in componentsInChildren)
{
if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name != "QuickRestartButton")
{
return val;
}
}
return null;
}
private static Button FindExistingRestartButton(GameObject settingsButtons)
{
Button val = null;
Button[] componentsInChildren = settingsButtons.GetComponentsInChildren<Button>(true);
foreach (Button val2 in componentsInChildren)
{
if ((Object)(object)val2 != (Object)null && ((Object)((Component)val2).gameObject).name == "QuickRestartButton")
{
if ((Object)(object)val == (Object)null)
{
val = val2;
}
else
{
Object.Destroy((Object)(object)((Component)val2).gameObject);
}
}
}
return val;
}
private static void PrepareRestartButton(GameObject buttonObject)
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
StripLocalization(buttonObject);
SetButtonText(buttonObject, "RESTART");
QuickRestartPlugin.RunCoroutine(EnsureButtonTextNextFrame(buttonObject));
Button component = buttonObject.GetComponent<Button>();
if (!((Object)(object)component == (Object)null))
{
((UnityEventBase)component.onClick).RemoveAllListeners();
ButtonClickedEvent onClick = component.onClick;
object obj = <>O.<0>__CancelDay;
if (obj == null)
{
UnityAction val = QuickRestartPlugin.CancelDay;
<>O.<0>__CancelDay = val;
obj = (object)val;
}
((UnityEvent)onClick).AddListener((UnityAction)obj);
}
}
private static IEnumerator EnsureButtonTextNextFrame(GameObject buttonObject)
{
yield return null;
if (QuickRestartPlugin.IsUnityObjectAlive(buttonObject))
{
SetButtonText(buttonObject, "RESTART");
}
}
private static void StripLocalization(GameObject buttonObject)
{
Component[] componentsInChildren = buttonObject.GetComponentsInChildren<Component>(true);
foreach (Component val in componentsInChildren)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
string fullName = ((object)val).GetType().FullName;
if (fullName != null && IsLocalizationComponent(fullName))
{
Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
if (val2 != null)
{
val2.enabled = false;
}
Object.DestroyImmediate((Object)(object)val);
}
}
}
private static bool IsLocalizationComponent(string typeName)
{
if (!typeName.StartsWith("Kamgam.LocalizationForSettings.", StringComparison.Ordinal) && !typeName.StartsWith("UnityEngine.Localization.Components.", StringComparison.Ordinal) && typeName.IndexOf("Localize", StringComparison.OrdinalIgnoreCase) < 0)
{
return typeName.IndexOf("Localization", StringComparison.OrdinalIgnoreCase) >= 0;
}
return true;
}
private static void SetButtonText(GameObject buttonObject, string textValue)
{
TMP_Text[] componentsInChildren = buttonObject.GetComponentsInChildren<TMP_Text>(true);
foreach (TMP_Text obj in componentsInChildren)
{
obj.text = textValue;
obj.SetText(textValue);
}
Text[] componentsInChildren2 = buttonObject.GetComponentsInChildren<Text>(true);
for (int i = 0; i < componentsInChildren2.Length; i++)
{
componentsInChildren2[i].text = textValue;
}
}
private static void ResetMenuInjection()
{
_lastSettingsButtons = null;
_restartButton = null;
}
private static IEnumerator InstantTransition(Bootstrap bootstrap, FieldInfo fiTransition, FieldInfo fiGameState, FieldInfo fiOnlineMode, GnomeHouse gnomeHouse, HomeManager homeManager, GameEndedReason reason)
{
fiTransition?.SetValue(bootstrap, true);
try
{
CancelActiveVortex(gnomeHouse);
GameProgressionManager instance = GameProgressionManager.Instance;
if ((Object)(object)instance != (Object)null)
{
PreserveDayCounter(instance);
QuickRestartPlugin.SetNetworkVar(instance, "n_timeActive", value: false);
QuickRestartPlugin.SetNetworkVar(instance, "n_karma", 0f);
QuickRestartPlugin.SetNetworkVar(instance, "n_currentGameTime", 0f);
instance.SelectedLevelIndex = -1;
GnomiumDeposit deposit = instance.Deposit;
if ((Object)(object)deposit != (Object)null)
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Resetting deposit game state.");
deposit.InitGameState();
}
StopTaskCallbacks();
TriggerGameEndedPlayerAction(instance);
}
GnomeHouse val = Object.FindObjectOfType<GnomeHouse>();
if (_depositWorldSaved && (Object)(object)((val != null) ? val.GnomiumDeposit : null) != (Object)null)
{
try
{
Transform transform = ((Component)val.GnomiumDeposit).transform;
transform.position = _savedDepositWorldPos;
transform.rotation = _savedDepositWorldRot;
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Restored deposit box: worldPos={_savedDepositWorldPos} worldRot={((Quaternion)(ref _savedDepositWorldRot)).eulerAngles}");
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Failed to restore deposit box: " + ex.Message));
}
}
else
{
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Skipped deposit box restore: saved={_depositWorldSaved}, gnomeHouse={(Object)(object)val != (Object)null}, deposit={(Object)(object)((val != null) ? val.GnomiumDeposit : null) != (Object)null}");
}
if ((Object)(object)homeManager != (Object)null)
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Moving house to plateau + assembly.");
homeManager.MoveHomeToPlateau();
homeManager.PerformAssembly(true);
}
object? obj = typeof(Bootstrap).GetField("gnomeHouse", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(bootstrap);
GnomeHouse val2 = (GnomeHouse)((obj is GnomeHouse) ? obj : null);
if ((Object)(object)val2 != (Object)null)
{
CancelActiveVortex(val2);
}
else
{
CancelActiveVortex(gnomeHouse);
}
yield return null;
yield return null;
Scene activeScene = SceneManager.GetActiveScene();
NetworkManager singleton = NetworkManager.Singleton;
if (((singleton != null) ? singleton.SceneManager : null) != null)
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Unloading gameplay scene.");
NetworkManager.Singleton.SceneManager.UnloadScene(activeScene);
float sceneTimeout = 10f;
while (sceneTimeout > 0f)
{
Scene activeScene2 = SceneManager.GetActiveScene();
if (activeScene2 != activeScene && ((Scene)(ref activeScene2)).IsValid())
{
break;
}
sceneTimeout -= Time.unscaledDeltaTime;
yield return null;
}
}
MethodInfo methodInfo = typeof(Bootstrap).GetProperty("State", BindingFlags.Instance | BindingFlags.Public)?.GetSetMethod(nonPublic: true);
if (methodInfo != null)
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Setting State via property setter.");
methodInfo.Invoke(bootstrap, new object[1] { (object)(GameState)0 });
}
else
{
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] No State setter found; using field.");
fiGameState?.SetValue(bootstrap, (object)(GameState)0);
}
if (fiOnlineMode != null && (bool)fiOnlineMode.GetValue(bootstrap))
{
LobbyManager component = ((Component)bootstrap).GetComponent<LobbyManager>();
if (component != null)
{
component.SetCanJoin(true);
}
}
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Starting lobby object reinitialization.");
QuickRestartPlugin.RunCoroutine(QuickRestartPlugin.DelayedLobbyReinitialize(bootstrap));
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Lobby transition complete.");
}
finally
{
object? obj2 = typeof(Bootstrap).GetField("gnomeHouse", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(bootstrap);
GnomeHouse val3 = (GnomeHouse)((obj2 is GnomeHouse) ? obj2 : null);
if ((Object)(object)val3 != (Object)null)
{
CancelActiveVortex(val3);
}
fiTransition?.SetValue(bootstrap, false);
ResetMenuInjection();
}
}
internal static void CancelActiveVortex(GnomeHouse gnomeHouse)
{
if ((Object)(object)gnomeHouse == (Object)null || !gnomeHouse.IsVortexActive)
{
return;
}
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Cancelling active house vortex.");
try
{
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
for (int i = 0; i < array.Length; i++)
{
RestorePlayerFromVortexState(array[i]);
}
((MonoBehaviour)gnomeHouse).StopAllCoroutines();
AccessTools.Field(typeof(GnomeHouse), "vortexAcceptingNewPlayers")?.SetValue(gnomeHouse, false);
AccessTools.Field(typeof(GnomeHouse), "currentVortexDirection")?.SetValue(gnomeHouse, 0);
AccessTools.Field(typeof(GnomeHouse), "playerBoundsChecker")?.SetValue(gnomeHouse, null);
AccessTools.Method(typeof(GnomeHouse), "ToggleVortexObject", (Type[])null, (Type[])null)?.Invoke(gnomeHouse, new object[1] { false });
AccessTools.Method(typeof(GnomeHouse), "OnVortexEnded", (Type[])null, (Type[])null)?.Invoke(gnomeHouse, Array.Empty<object>());
string[] array2 = new string[4] { "playersInVortex", "playersAlreadyInVortexThisCycle", "playersAlreadyReceivedImpulse", "playersWhoGotStuckOnPlateau" };
foreach (string text in array2)
{
try
{
ClearPrivateList(gnomeHouse, text);
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] List clear skipped (" + text + "): " + ex.Message));
}
}
}
catch (Exception ex2)
{
Exception innerException = ex2.InnerException;
if (innerException != null)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Active vortex cleanup failed: " + ex2.Message + " | Inner: " + innerException.GetType().Name + ": " + innerException.Message));
}
else
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Active vortex cleanup failed: " + ex2.Message));
}
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Vortex cleanup stack: " + ex2.StackTrace));
}
}
private static void RestorePlayerFromVortexState(PlayerNetworking player)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)player == (Object)null)
{
return;
}
try
{
if ((int)((GameEntityBase)player).CurrentContainment != 0)
{
((GameEntityBase)player).SetContainmentState((ContainmentState)0);
}
player.ToggleRagdollGravity(true);
if (((NetworkBehaviour)player).IsLocalPlayer)
{
player.StatusEffects.OnVortexLeft();
}
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)$"[QuickRestart] Player vortex state cleanup failed for {((NetworkBehaviour)player).NetworkObjectId} (non-fatal): {ex.Message}");
}
}
private static void ClearPrivateList(object owner, string fieldName)
{
object obj = AccessTools.Field(owner.GetType(), fieldName)?.GetValue(owner);
obj?.GetType().GetMethod("Clear", Type.EmptyTypes)?.Invoke(obj, Array.Empty<object>());
}
private static void PreserveDayCounter(GameProgressionManager progression)
{
int value = Math.Max(0, progression.CurrentLevel - 1);
int value2 = progression.CurrentDay + 1;
QuickRestartPlugin.SetNetworkVar(progression, "n_level", value);
QuickRestartPlugin.SetNetworkVar(progression, "n_day", value2);
}
internal static void TriggerGameEndedPlayerAction(GameProgressionManager progression)
{
try
{
MethodInfo method = typeof(GameProgressionManager).GetMethod("TriggerGameEventRpc", BindingFlags.Instance | BindingFlags.NonPublic);
if (!(method == null))
{
object obj = Enum.Parse(method.GetParameters()[0].ParameterType, "On_Game_Ended_PLAYER_ACTION");
method.Invoke(progression, new object[1] { obj });
}
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Game-ended UI cleanup event failed (non-fatal): " + ex.Message));
}
}
internal static void StopTaskCallbacks()
{
try
{
PlayerTaskManager val = Object.FindObjectOfType<PlayerTaskManager>();
if ((Object)(object)val == (Object)null)
{
return;
}
QuickRestartPlugin.Logger.LogInfo((object)"[QuickRestart] Stopping task callbacks.");
if (!(typeof(PlayerTaskManager).GetField("allTasks", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val) is List<PlayerTaskBase> list))
{
return;
}
foreach (PlayerTaskBase item in list)
{
try
{
item.StopListeningToCallbacks();
}
catch
{
}
}
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] Task callback cleanup failed (non-fatal): " + ex.Message));
}
}
internal static IEnumerator RecoverLobbyPlayersAndEquipment()
{
yield return WaitForCurrentHomeReady();
int num = RepositionAllPlayersAtLobbySpawn();
if (num > 0)
{
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Repositioned {num} players at lobby mouth spawn.");
float elapsed = 0f;
while (elapsed < 2f && AnyPlayerDead())
{
elapsed += Time.unscaledDeltaTime;
yield return null;
}
QuickRestartPlugin.ResetPlayerControllerUiState();
}
yield return RestoreEquipmentUntilStable();
}
private static IEnumerator WaitForCurrentHomeReady()
{
float elapsed = 0f;
while (elapsed < 10f)
{
HomeManager currentPlayerHome = GetCurrentPlayerHome();
if ((Object)(object)currentPlayerHome != (Object)null && !currentPlayerHome.IsLoadingHome && (Object)(object)currentPlayerHome.CurrentHome != (Object)null)
{
yield break;
}
elapsed += Time.unscaledDeltaTime;
yield return null;
}
QuickRestartPlugin.Logger.LogWarning((object)"[QuickRestart] Timed out waiting for current home before lobby recovery.");
}
private static int RepositionAllPlayersAtLobbySpawn()
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
GnomeHouse currentGnomeHouse = GetCurrentGnomeHouse();
HomeManager val = ((currentGnomeHouse != null) ? currentGnomeHouse.PlayerHome : null) ?? GetCurrentPlayerHome();
if ((Object)(object)currentGnomeHouse == (Object)null && (Object)(object)((val != null) ? val.CurrentHome : null) == (Object)null)
{
return 0;
}
int num = 0;
Vector3 val2 = (((Object)(object)((val != null) ? val.CurrentHome : null) != (Object)null) ? val.CurrentHome.PlayerRespawnPosition : (((Object)(object)currentGnomeHouse != (Object)null) ? currentGnomeHouse.PlayerSpawnPosition : Vector3.zero));
QuickRestartPlugin.Logger.LogInfo((object)string.Format("[QuickRestart] Respawn position: {0} (homeCurrentHomePos={1})", val2, ((Object)(object)((val != null) ? val.CurrentHome : null) != (Object)null) ? ((object)((Component)val.CurrentHome).transform.position/*cast due to .constrained prefix*/).ToString() : "null"));
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
foreach (PlayerNetworking val3 in array)
{
if ((Object)(object)val3 == (Object)null || (Object)(object)val3.Health == (Object)null)
{
continue;
}
try
{
if (((HealthBase)val3.Health).Dead)
{
val3.InstantRespawn(val2);
}
else if ((Object)(object)((NetworkBehaviour)val3).NetworkObject != (Object)null)
{
((Component)((NetworkBehaviour)val3).NetworkObject).transform.position = val2;
}
else
{
((Component)val3).transform.position = val2;
}
num++;
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)$"[QuickRestart] Player reposition failed for {((NetworkBehaviour)val3).NetworkObjectId} (non-fatal): {ex.Message}");
}
}
return num;
}
internal static bool AnyPlayerDead()
{
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
foreach (PlayerNetworking val in array)
{
if ((Object)(object)((val != null) ? val.Health : null) != (Object)null && ((HealthBase)val.Health).Dead)
{
return true;
}
}
return false;
}
internal static GnomeHouse GetCurrentGnomeHouse()
{
GameProgressionManager instance = GameProgressionManager.Instance;
if (instance == null)
{
return null;
}
GnomiumDeposit deposit = instance.Deposit;
if (deposit == null)
{
return null;
}
return deposit.House;
}
private static HomeManager GetCurrentPlayerHome()
{
GameProgressionManager instance = GameProgressionManager.Instance;
if (instance == null)
{
return null;
}
GnomiumDeposit deposit = instance.Deposit;
if (deposit == null)
{
return null;
}
GnomeHouse house = deposit.House;
if (house == null)
{
return null;
}
return house.PlayerHome;
}
internal static void SnapshotEquipment()
{
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_0327: Unknown result type (might be due to invalid IL or missing references)
//IL_032c: Unknown result type (might be due to invalid IL or missing references)
//IL_0343: Unknown result type (might be due to invalid IL or missing references)
//IL_034d: Unknown result type (might be due to invalid IL or missing references)
//IL_049c: Unknown result type (might be due to invalid IL or missing references)
//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
//IL_037f: Unknown result type (might be due to invalid IL or missing references)
EquipmentSnapshots.Clear();
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
foreach (PlayerNetworking val in array)
{
if ((Object)(object)val == (Object)null || (Object)(object)val.Inventory == (Object)null || (Object)(object)((NetworkBehaviour)val).NetworkObject == (Object)null)
{
continue;
}
EquipmentSnapshot equipmentSnapshot = new EquipmentSnapshot
{
NetworkObjectId = ((NetworkBehaviour)val).NetworkObjectId,
OwnerClientId = ((NetworkBehaviour)val).OwnerClientId
};
foreach (InventoryItem content in ((InventoryBase)val.Inventory).Contents)
{
InventoryItem current = content;
if (((InventoryItem)(ref current)).IsValidItem)
{
equipmentSnapshot.Items.Add(current);
}
}
EquipmentSnapshots.Add(equipmentSnapshot);
}
int num = 0;
foreach (EquipmentSnapshot equipmentSnapshot7 in EquipmentSnapshots)
{
num += equipmentSnapshot7.Items.Count;
}
int num2 = 0;
for (int j = 0; j < EquipmentSnapshots.Count; j++)
{
EquipmentSnapshot equipmentSnapshot2 = EquipmentSnapshots[j];
if (equipmentSnapshot2.Items.Count > 0)
{
continue;
}
EquipmentSnapshot equipmentSnapshot3 = FindMatchingLastGood(equipmentSnapshot2);
if (equipmentSnapshot3 == null || equipmentSnapshot3.Items.Count <= 0)
{
continue;
}
foreach (InventoryItem item in equipmentSnapshot3.Items)
{
_ = item;
equipmentSnapshot2.Items.Clear();
}
equipmentSnapshot2.Items.AddRange(equipmentSnapshot3.Items);
num2++;
}
int num3 = 0;
foreach (EquipmentSnapshot item2 in LastGoodEquipment)
{
bool flag = false;
for (int k = 0; k < EquipmentSnapshots.Count; k++)
{
if (EquipmentSnapshots[k].OwnerClientId == item2.OwnerClientId || EquipmentSnapshots[k].NetworkObjectId == item2.NetworkObjectId)
{
flag = true;
break;
}
}
if (!flag)
{
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Player {item2.OwnerClientId} networking object gone; restoring {item2.Items.Count} items from last known good.");
EquipmentSnapshot equipmentSnapshot4 = new EquipmentSnapshot
{
NetworkObjectId = item2.NetworkObjectId,
OwnerClientId = item2.OwnerClientId
};
equipmentSnapshot4.Items.AddRange(item2.Items);
EquipmentSnapshots.Add(equipmentSnapshot4);
num3++;
}
}
int num4 = 0;
for (int l = 0; l < EquipmentSnapshots.Count; l++)
{
EquipmentSnapshot equipmentSnapshot5 = EquipmentSnapshots[l];
EquipmentSnapshot equipmentSnapshot6 = FindMatchingLastGood(equipmentSnapshot5);
if (equipmentSnapshot6 == null || equipmentSnapshot6.Items.Count <= equipmentSnapshot5.Items.Count)
{
continue;
}
int num5 = 0;
foreach (InventoryItem item3 in equipmentSnapshot6.Items)
{
bool flag2 = false;
foreach (InventoryItem item4 in equipmentSnapshot5.Items)
{
if (item4.slotIndex == item3.slotIndex)
{
flag2 = true;
break;
}
}
if (!flag2)
{
equipmentSnapshot5.Items.Add(item3);
num5++;
}
}
if (num5 > 0)
{
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Supplemented {num5} missing items from LastGoodEquipment for player {equipmentSnapshot5.OwnerClientId} (snapshot had {equipmentSnapshot5.Items.Count - num5}, last-good had {equipmentSnapshot6.Items.Count}).");
num4++;
}
}
if (num2 > 0 || num3 > 0 || num4 > 0)
{
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Applied last-good fallback: {num2} empty players, {num3} missing players, {num4} supplemented.");
}
int num6 = 0;
foreach (EquipmentSnapshot equipmentSnapshot8 in EquipmentSnapshots)
{
num6 += equipmentSnapshot8.Items.Count;
List<string> list = new List<string>();
foreach (InventoryItem item5 in equipmentSnapshot8.Items)
{
InventoryItem current6 = item5;
list.Add($"[slot:{current6.slotIndex} item:{((InventoryItem)(ref current6)).ItemIndex}]");
}
QuickRestartPlugin.Logger.LogInfo((object)string.Format("[QuickRestart] Snapshot player {0}: {1} items — {2}", equipmentSnapshot8.OwnerClientId, equipmentSnapshot8.Items.Count, string.Join(", ", list)));
}
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Snapshotted equipment for {EquipmentSnapshots.Count} players ({num6} items).");
}
private static IEnumerator RestoreEquipmentUntilStable()
{
_phase1CompletePlayers.Clear();
float elapsed = 0f;
int attempts = 0;
while (elapsed < 8f)
{
if (IsNativePostGameCleanupActive())
{
elapsed += Time.unscaledDeltaTime;
yield return null;
continue;
}
attempts++;
if (RestoreEquipmentSnapshot() && elapsed >= 1f)
{
break;
}
float wait = 0f;
while (wait < 0.5f)
{
wait += Time.unscaledDeltaTime;
elapsed += Time.unscaledDeltaTime;
yield return null;
}
}
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Equipment restore stabilization finished after {attempts} attempts.");
}
private static bool IsNativePostGameCleanupActive()
{
GameProgressionManager instance = GameProgressionManager.Instance;
GnomiumDeposit val = ((instance != null) ? instance.Deposit : null);
if ((Object)(object)val != (Object)null)
{
if (!val.PreventingRespawns)
{
return val.PapyrusIsAnimating;
}
return true;
}
return false;
}
internal static bool RestoreEquipmentSnapshot()
{
//IL_0291: Unknown result type (might be due to invalid IL or missing references)
//IL_0296: Unknown result type (might be due to invalid IL or missing references)
//IL_0298: Unknown result type (might be due to invalid IL or missing references)
//IL_0334: Unknown result type (might be due to invalid IL or missing references)
//IL_0339: Unknown result type (might be due to invalid IL or missing references)
//IL_033b: Unknown result type (might be due to invalid IL or missing references)
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_01de: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
//IL_034e: Unknown result type (might be due to invalid IL or missing references)
//IL_0353: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
//IL_036c: Unknown result type (might be due to invalid IL or missing references)
//IL_0211: Unknown result type (might be due to invalid IL or missing references)
//IL_039c: Unknown result type (might be due to invalid IL or missing references)
//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
//IL_03da: Unknown result type (might be due to invalid IL or missing references)
//IL_041e: Unknown result type (might be due to invalid IL or missing references)
//IL_0423: Unknown result type (might be due to invalid IL or missing references)
//IL_0437: Unknown result type (might be due to invalid IL or missing references)
if (EquipmentSnapshots.Count == 0)
{
QuickRestartPlugin.Logger.LogWarning((object)"[QuickRestart] No equipment snapshot is available to restore.");
return true;
}
int num = 0;
int num2 = 0;
int num3 = 0;
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
foreach (PlayerNetworking val in array)
{
if ((Object)(object)val == (Object)null || (Object)(object)val.Inventory == (Object)null || (Object)(object)((NetworkBehaviour)val).NetworkObject == (Object)null)
{
continue;
}
EquipmentSnapshot equipmentSnapshot = FindEquipmentSnapshot(val);
if (equipmentSnapshot == null)
{
continue;
}
try
{
if (InventoryMatchesSnapshot(val.Inventory, equipmentSnapshot.Items))
{
num3++;
continue;
}
if (equipmentSnapshot.Items.Count == 0)
{
num3++;
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Player {((NetworkBehaviour)val).OwnerClientId} snapshot is empty (was dead at capture); keeping lobby spawn items.");
continue;
}
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Restoring player {((NetworkBehaviour)val).OwnerClientId}: snapshot has {equipmentSnapshot.Items.Count} items, player has {((InventoryBase)val.Inventory).Contents.Count} items, SlotCount={((InventoryBase)val.Inventory).SlotCount}, IsHost={NetworkManager.Singleton.IsHost}");
try
{
GameObject gameObject = ((Component)val.Inventory).gameObject;
if ((Object)(object)gameObject != (Object)null && !gameObject.activeInHierarchy)
{
gameObject.SetActive(true);
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Re-activated disabled inventory for player {((NetworkBehaviour)val).NetworkObjectId}.");
}
}
catch
{
}
int num4 = 0;
int num5 = 0;
List<InventoryItem> list = new List<InventoryItem>();
if (!_phase1CompletePlayers.Contains(((NetworkBehaviour)val).OwnerClientId))
{
((InventoryBase)val.Inventory).ClearInventory();
foreach (InventoryItem item in equipmentSnapshot.Items)
{
InventoryItem current = item;
if (current.slotIndex <= 1)
{
if (((InventoryBase)val.Inventory).TryAddItemToSlot(((InventoryItem)(ref current)).InstanceData, (int)current.slotIndex) > 0)
{
num4++;
}
else
{
list.Add(current);
}
}
}
try
{
if ((Object)(object)val.Equipment != (Object)null)
{
val.Equipment.UpdateEquipmentState();
}
}
catch (Exception ex)
{
QuickRestartPlugin.Logger.LogWarning((object)("[QuickRestart] UpdateEquipmentState failed: " + ex.Message));
}
int slotCount = ((InventoryBase)val.Inventory).SlotCount;
byte b = 0;
foreach (InventoryItem item2 in equipmentSnapshot.Items)
{
if (item2.slotIndex > b)
{
b = item2.slotIndex;
}
}
if (slotCount <= b)
{
((InventoryBase)val.Inventory).ResizeInventory(b + 1);
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Resized inventory from {slotCount} to {b + 1} for player {((NetworkBehaviour)val).NetworkObjectId} (backpack slot sync).");
}
_phase1CompletePlayers.Add(((NetworkBehaviour)val).OwnerClientId);
continue;
}
foreach (InventoryItem item3 in equipmentSnapshot.Items)
{
InventoryItem current3 = item3;
if (current3.slotIndex > 1)
{
if (((InventoryBase)val.Inventory).TryAddItemToSlot(((InventoryItem)(ref current3)).InstanceData, (int)current3.slotIndex) > 0)
{
num4++;
}
else
{
list.Add(current3);
}
}
}
foreach (InventoryItem item4 in list)
{
InventoryItem current4 = item4;
if (((InventoryBase)val.Inventory).TryAddItem(((InventoryItem)(ref current4)).InstanceData) > 0)
{
num5++;
continue;
}
QuickRestartPlugin.Logger.LogWarning((object)($"[QuickRestart] TryAddItem failed for item {((InventoryItem)(ref current4)).ItemIndex} (slot {current4.slotIndex}); scanning " + $"{((InventoryBase)val.Inventory).SlotCount} slots for empty spot..."));
for (int j = 0; j < ((InventoryBase)val.Inventory).SlotCount; j++)
{
InventoryItem itemInSlot = ((InventoryBase)val.Inventory).GetItemInSlot(j);
if (!((InventoryItem)(ref itemInSlot)).IsValidItem && ((InventoryBase)val.Inventory).TryAddItemToSlot(((InventoryItem)(ref current4)).InstanceData, j) > 0)
{
num5++;
break;
}
}
}
num2 = num4 + num5;
num++;
}
catch (Exception ex2)
{
QuickRestartPlugin.Logger.LogWarning((object)$"[QuickRestart] Equipment restore failed for player {((NetworkBehaviour)val).NetworkObjectId} (non-fatal): {ex2.Message}");
}
}
bool result = num + num3 >= EquipmentSnapshots.Count;
QuickRestartPlugin.Logger.LogInfo((object)$"[QuickRestart] Restored equipment snapshot for {num} players ({num2} items); {num3} already matched.");
return result;
}
internal static bool HasLastGoodEquipment()
{
if (LastGoodEquipment.Count == 0)
{
return false;
}
foreach (EquipmentSnapshot item in LastGoodEquipment)
{
if (item.Items.Count == 0)
{
continue;
}
bool flag = false;
PlayerNetworking[] array = Object.FindObjectsOfType<PlayerNetworking>();
foreach (PlayerNetworking val in array)
{
if ((Object)(object)val != (Object)null && (((NetworkBehaviour)val).OwnerClientId == item.OwnerClientId || ((NetworkBehaviour)val).NetworkObjectId == item.NetworkObjectId))
{
flag = true;
break;
}
}
if (!flag)
{
return true;
}
}
return false;
}
private static EquipmentSnapshot FindMatchingLastGood(EquipmentSnapshot snap)
{
foreach (EquipmentSnapshot item in LastGoodEquipment)
{
if (item.OwnerClientId == snap.OwnerClientId)
{
return item;
}
}
foreach (EquipmentSnapshot item2 in LastGoodEquipment)
{
if (item2.NetworkObjectId == snap.NetworkObjectId)
{
return item2;
}
}
return null;
}
private static EquipmentSnapshot FindEquipmentSnapshot(PlayerNetworking player)
{
foreach (EquipmentSnapshot equipmentSnapshot in EquipmentSnapshots)
{
if (equipmentSnapshot.OwnerClientId == ((NetworkBehaviour)player).OwnerClientId)
{
return equipmentSnapshot;
}
}
foreach (EquipmentSnapshot equipmentSnapshot2 in EquipmentSnapshots)
{
if (equipmentSnapshot2.NetworkObjectId == ((NetworkBehaviour)player).NetworkObjectId)
{
return equipmentSnapshot2;
}
}
return null;
}
private static bool InventoryMatchesSnapshot(PlayerInventory inventory, List<InventoryItem> snapshot)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
if (((InventoryBase)inventory).Contents.Count != snapshot.Count)
{
return false;
}
foreach (InventoryItem item in snapshot)
{
InventoryItem current = item;
InventoryItem itemInSlot = ((InventoryBase)inventory).GetItemInSlot((int)current.slotIndex);
if (!((InventoryItem)(ref itemInSlot)).IsValidItem || ((InventoryItem)(ref itemInSlot)).ItemIndex != ((InventoryItem)(ref current)).ItemIndex || ((InventoryItem)(ref itemInSlot)).ItemCount != ((InventoryItem)(ref current)).ItemCount || Math.Abs(((InventoryItem)(ref itemInSlot)).Durability - ((InventoryItem)(ref current)).Durability) > 0.01f)
{
return false;
}
}
return true;
}
}
}