Decompiled source of Quick Restart v2.0.0

tony4twentys-Quick Restart.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Quick Restart")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Quick Restart")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("89a2838d-6516-48d0-bfaf-bda1077942b6")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("tony4twentys.quickrestart", "Quick Restart", "3.2.0")]
public class QuickRestartPlugin : BaseUnityPlugin, IOnEventCallback, IInRoomCallbacks, IMatchmakingCallbacks
{
	public const string ModVersion = "3.2.0";

	public const string RoomModPropertyKey = "QR_ModVersion";

	public const byte IslandRestartEventCode = 177;

	private const float ModPresenceGraceSeconds = 0.75f;

	private bool shouldAutoRestart;

	private bool useRandomSeed;

	private bool useDailySeed;

	private bool hasAutoClickedMainMenuButton;

	private bool restartInProgress;

	private ConfigEntry<KeyCode> menuKey;

	private ConfigEntry<bool> skipAirportInMultiplayer;

	private ConfigEntry<bool> skipSplashScreen;

	private ConfigEntry<float> mainMenuClickDelay;

	private ConfigEntry<bool> enableMainMenuAutoClick;

	private ConfigEntry<string> mainMenuButtonChoice;

	private ConfigEntry<float> menuX;

	private ConfigEntry<float> menuY;

	private ConfigEntry<bool> enableHotkeys;

	private ConfigEntry<KeyCode> hotkeyAscentKiosk;

	private ConfigEntry<KeyCode> hotkeyQuickRestart;

	private ConfigEntry<KeyCode> hotkeyDailySeed;

	private ConfigEntry<KeyCode> hotkeyReturnToAirport;

	private ConfigEntry<KeyCode> hotkeyRandomSeed;

	private bool showMenu;

	private Rect menuRect;

	private void Awake()
	{
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "MenuKey", (KeyCode)291, "Key to open the Quick Restart menu.");
		skipAirportInMultiplayer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SkipAirportInMultiplayer", true, "MID-RUN MULTIPLAYER ONLY: when every connected player has Quick Restart, skip the airport and reload the island directly. If any player is missing this mod, the airport detour is used automatically. WARNING: Skipping the airport in multiplayer can cause a few seconds of movement/action desync after loading (especially with other mods). Set this to false to always return to the airport first in multiplayer (more reliable). Solo/offline always skips the airport regardless of this setting. Starting from the Airport scene always uses the vanilla kiosk.");
		skipSplashScreen = ((BaseUnityPlugin)this).Config.Bind<bool>("MainMenu", "SkipSplashScreen", true, "Skip the splash screen when the game starts.");
		enableMainMenuAutoClick = ((BaseUnityPlugin)this).Config.Bind<bool>("MainMenu", "EnableAutoClick", true, "Automatically click a button when reaching the main menu.");
		mainMenuButtonChoice = ((BaseUnityPlugin)this).Config.Bind<string>("MainMenu", "ButtonChoice", "Button_PlayWithFriends", "Which button to automatically click: 'Button_PlayWithFriends' or 'Button_PlaySolo'.");
		mainMenuClickDelay = ((BaseUnityPlugin)this).Config.Bind<float>("MainMenu", "MainMenuClickDelay", 1f, "Delay before clicking button when reaching main menu (seconds).");
		menuX = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "PositionX", 50f, "X position of the menu window.");
		menuY = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "PositionY", 50f, "Y position of the menu window.");
		enableHotkeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Hotkeys", "EnableHotkeys", false, "Enable hotkey functionality for quick actions.");
		hotkeyAscentKiosk = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "AscentKioskKey", (KeyCode)282, "Hotkey for Ascent Kiosk interaction.");
		hotkeyQuickRestart = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "QuickRestartKey", (KeyCode)283, "Hotkey for Quick Restart.");
		hotkeyDailySeed = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "DailySeedKey", (KeyCode)284, "Hotkey for Daily Seed Start.");
		hotkeyReturnToAirport = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "ReturnToAirportKey", (KeyCode)285, "Hotkey for Return to Airport.");
		hotkeyRandomSeed = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "RandomSeedKey", (KeyCode)286, "Hotkey for Random Seed Start.");
		menuRect = new Rect(menuX.Value, menuY.Value, 300f, 400f);
		SceneManager.sceneLoaded += OnSceneLoaded;
		PhotonNetwork.AddCallbackTarget((object)this);
		if (skipSplashScreen.Value)
		{
			((MonoBehaviour)this).StartCoroutine(SkipSplashScreenCoroutine());
		}
	}

	private void OnDestroy()
	{
		PhotonNetwork.RemoveCallbackTarget((object)this);
		SceneManager.sceneLoaded -= OnSceneLoaded;
	}

	public void OnEvent(EventData photonEvent)
	{
		if (photonEvent.Code != 177)
		{
			return;
		}
		if (!(photonEvent.CustomData is object[] array) || array.Length < 3)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Ignored restart event with invalid payload.");
			return;
		}
		string text = array[0] as string;
		if (string.IsNullOrEmpty(text))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Ignored restart event with empty scene name.");
			return;
		}
		int num = ((array[1] is int num2) ? num2 : ((array[1] is byte b) ? b : 0));
		byte[] serializedRunSettings = Array.Empty<byte>();
		if (array[2] is byte[] array2)
		{
			serializedRunSettings = array2;
		}
		else if (array[2] is string s)
		{
			try
			{
				serializedRunSettings = Convert.FromBase64String(s);
			}
			catch
			{
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"Quick Restart: Restart event received (scene={text}, ascent={num}).");
		BeginIslandLoadLikeVanilla(text, num, serializedRunSettings, networked: true);
		restartInProgress = false;
	}

	void IInRoomCallbacks.OnPlayerEnteredRoom(Player newPlayer)
	{
		PublishModPresence();
	}

	void IInRoomCallbacks.OnPlayerLeftRoom(Player otherPlayer)
	{
	}

	void IInRoomCallbacks.OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
	{
	}

	void IInRoomCallbacks.OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
	{
	}

	void IInRoomCallbacks.OnMasterClientSwitched(Player newMasterClient)
	{
		PublishModPresence();
	}

	void IMatchmakingCallbacks.OnJoinedRoom()
	{
		PublishModPresence();
	}

	void IMatchmakingCallbacks.OnCreatedRoom()
	{
	}

	void IMatchmakingCallbacks.OnCreateRoomFailed(short returnCode, string message)
	{
	}

	void IMatchmakingCallbacks.OnFriendListUpdate(List<FriendInfo> friendList)
	{
	}

	void IMatchmakingCallbacks.OnJoinRandomFailed(short returnCode, string message)
	{
	}

	void IMatchmakingCallbacks.OnJoinRoomFailed(short returnCode, string message)
	{
	}

	void IMatchmakingCallbacks.OnLeftRoom()
	{
	}

	private void PublishModPresence()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Expected O, but got Unknown
		//IL_003b: Expected O, but got Unknown
		if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null)
		{
			Player localPlayer = PhotonNetwork.LocalPlayer;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"QR_ModVersion", (object)"3.2.0");
			localPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
		}
	}

	private IEnumerator SkipSplashScreenCoroutine()
	{
		yield return null;
		try
		{
			SplashScreen.Stop((StopBehavior)0);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Splash screen skipped successfully.");
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Quick Restart: Could not skip splash screen: " + ex2.Message));
		}
		((MonoBehaviour)this).StartCoroutine(ForceLoadTitleScene());
	}

	private IEnumerator ForceLoadTitleScene()
	{
		yield return (object)new WaitForSeconds(0.5f);
		try
		{
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name != "Title")
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Force loading Title scene to skip startup screens.");
				SceneManager.LoadScene("Title", (LoadSceneMode)0);
			}
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			((BaseUnityPlugin)this).Logger.LogError((object)("Quick Restart: Error force loading Title scene: " + ex2.Message));
		}
	}

	private void Update()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		if (!CanUseControls())
		{
			return;
		}
		if (Input.GetKeyDown(menuKey.Value))
		{
			showMenu = !showMenu;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Quick Restart: Menu " + (showMenu ? "opened" : "closed")));
			if (!showMenu)
			{
				Cursor.lockState = (CursorLockMode)1;
				Cursor.visible = false;
			}
		}
		if (enableHotkeys.Value)
		{
			HandleHotkeys();
		}
	}

	private static bool CanUseControls()
	{
		if (PhotonNetwork.OfflineMode)
		{
			return true;
		}
		return PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient;
	}

	private static bool IsSoloSession()
	{
		if (PhotonNetwork.OfflineMode)
		{
			return true;
		}
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return true;
		}
		return PhotonNetwork.CurrentRoom.PlayerCount <= 1;
	}

	private void HandleHotkeys()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: 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)
		if (Input.GetKeyDown(hotkeyAscentKiosk.Value))
		{
			CallInteractCastFinished();
		}
		if (Input.GetKeyDown(hotkeyQuickRestart.Value))
		{
			BeginQuickRestart(randomSeed: false, dailySeed: false);
		}
		if (Input.GetKeyDown(hotkeyDailySeed.Value))
		{
			BeginQuickRestart(randomSeed: false, dailySeed: true);
		}
		if (Input.GetKeyDown(hotkeyReturnToAirport.Value))
		{
			ReturnToAirportOnly();
		}
		if (Input.GetKeyDown(hotkeyRandomSeed.Value))
		{
			BeginQuickRestart(randomSeed: true, dailySeed: false);
		}
	}

	private void OnGUI()
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Expected O, but got Unknown
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		if (showMenu)
		{
			menuRect = new Rect(menuX.Value, menuY.Value, 300f, 400f);
			menuRect = GUI.Window(0, menuRect, new WindowFunction(DrawMenuWindow), "Quick Restart Menu");
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}
	}

	private void DrawMenuWindow(int windowID)
	{
		GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.ExpandWidth(true),
			GUILayout.ExpandHeight(true)
		});
		GUILayout.Label("Quick Restart Options", GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		GUILayout.Label(enableHotkeys.Value ? "Hotkeys: F1-F5 (Enabled)" : "Hotkeys: Disabled", GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		GUILayout.Space(10f);
		DrawButton("Ascent Kiosk", hotkeyAscentKiosk, CallInteractCastFinished);
		DrawButton("Quick Restart", hotkeyQuickRestart, delegate
		{
			BeginQuickRestart(randomSeed: false, dailySeed: false);
		});
		DrawButton("Daily Seed Start", hotkeyDailySeed, delegate
		{
			BeginQuickRestart(randomSeed: false, dailySeed: true);
		});
		DrawButton("Return to Airport", hotkeyReturnToAirport, ReturnToAirportOnly);
		GUILayout.Space(10f);
		GUILayout.Label("Terrain Randomizer", GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		GUILayout.Space(5f);
		DrawButton("Random Seed Start", hotkeyRandomSeed, delegate
		{
			BeginQuickRestart(randomSeed: true, dailySeed: false);
		});
		GUILayout.Space(10f);
		if (GUILayout.Button("Close Menu", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			showMenu = false;
		}
		GUILayout.EndVertical();
		GUI.DragWindow();
	}

	private void DrawButton(string label, ConfigEntry<KeyCode> hotkey, Action action)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		string text = (enableHotkeys.Value ? $"{label} ({hotkey.Value})" : label);
		if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }))
		{
			action();
			showMenu = false;
		}
	}

	private void BeginQuickRestart(bool randomSeed, bool dailySeed)
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		if (restartInProgress)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Restart already in progress.");
			return;
		}
		useRandomSeed = randomSeed;
		useDailySeed = dailySeed;
		if (dailySeed)
		{
			SetShouldRandomise(value: false);
		}
		else if (randomSeed)
		{
			SetShouldRandomise(value: true);
			SetNewRandomSeed();
		}
		Scene activeScene = SceneManager.GetActiveScene();
		if (((Scene)(ref activeScene)).name == "Airport")
		{
			if (dailySeed || randomSeed)
			{
				((MonoBehaviour)this).StartCoroutine(WaitAndStartGameFromAirport());
			}
			else
			{
				TryStartGameFromAirport();
			}
		}
		else
		{
			((MonoBehaviour)this).StartCoroutine(MidRunRestartRoutine());
		}
	}

	private IEnumerator MidRunRestartRoutine()
	{
		restartInProgress = true;
		PublishModPresence();
		if (useDailySeed || useRandomSeed)
		{
			yield return (object)new WaitForSecondsRealtime(0.5f);
		}
		if (IsSoloSession())
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Solo/offline mid-run — skipping airport.");
			BeginIslandLoadLikeVanilla(ResolveIslandSceneName(), Ascents.currentAscent, RunSettings.GetSerializedRunSettings(), PhotonNetwork.InRoom && !PhotonNetwork.OfflineMode);
			restartInProgress = false;
			yield break;
		}
		yield return WaitForModPresence(0.75f);
		bool allHaveMod = AllConnectedPlayersHaveMod();
		if (skipAirportInMultiplayer.Value && allHaveMod)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: All players have Quick Restart — skipping airport (synchronized island load).");
			if (!BroadcastSkipAirportRestart())
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Skip-airport broadcast failed — falling back to airport detour.");
				TriggerReturnToAirport(autoRestart: true);
				restartInProgress = false;
			}
		}
		else
		{
			if (!allHaveMod)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Quick Restart: Missing mod on: " + DescribeMissingModPlayers() + ". Using airport detour."));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: SkipAirportInMultiplayer is OFF — using airport detour.");
			}
			TriggerReturnToAirport(autoRestart: true);
			restartInProgress = false;
		}
	}

	private bool BroadcastSkipAirportRestart()
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Expected O, but got Unknown
		if (!PhotonNetwork.IsMasterClient)
		{
			return false;
		}
		string text = ResolveIslandSceneName();
		int currentAscent = Ascents.currentAscent;
		byte[] inArray = RunSettings.GetSerializedRunSettings() ?? Array.Empty<byte>();
		bool flag = PhotonNetwork.RaiseEvent((byte)177, (object)new object[3]
		{
			text,
			currentAscent,
			Convert.ToBase64String(inArray)
		}, new RaiseEventOptions
		{
			Receivers = (ReceiverGroup)1
		}, SendOptions.SendReliable);
		if (flag)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Quick Restart: Sent skip-airport restart to all players for '" + text + "'."));
		}
		return flag;
	}

	private void BeginIslandLoadLikeVanilla(string sceneName, int ascent, byte[] serializedRunSettings, bool networked)
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		if (LoadingScreenHandler.loading)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Already loading — ignoring duplicate island load.");
			return;
		}
		MenuWindow.CloseAllWindows();
		GameHandler.AddStatus<SceneSwitchingStatus>((GameStatus)new SceneSwitchingStatus());
		Debug.Log((object)("Begin scene load RPC: " + sceneName));
		Ascents.currentAscent = ascent;
		try
		{
			if (serializedRunSettings != null && serializedRunSettings.Length != 0)
			{
				GameUtils.ApplySerializedRunSettings(serializedRunSettings);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Quick Restart: ApplySerializedRunSettings failed (" + ex.Message + "); continuing load."));
		}
		LoadingScreenHandler instance = RetrievableResourceSingleton<LoadingScreenHandler>.Instance;
		instance.Load((LoadingScreenType)1, (Action)null, new IEnumerator[1] { instance.LoadSceneProcess(sceneName, networked, true, 0f) });
	}

	private static string ResolveIslandSceneName()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			int nextLevelIndexOrFallback = GameHandler.GetService<NextLevelService>().NextLevelIndexOrFallback;
			string text = SingletonAsset<MapBaker>.Instance.GetLevel(nextLevelIndexOrFallback + NextLevelService.debugLevelIndexOffset);
			if (string.IsNullOrEmpty(text))
			{
				text = "WilIsland";
			}
			return text;
		}
		catch
		{
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name;
		}
	}

	private void ReturnToAirportOnly()
	{
		shouldAutoRestart = false;
		TriggerReturnToAirport(autoRestart: false);
	}

	private void TriggerReturnToAirport(bool autoRestart)
	{
		GUIManager instance = GUIManager.instance;
		if (instance != null)
		{
			EndScreen endScreen = instance.endScreen;
			if (((endScreen != null) ? new bool?(((MenuWindow)endScreen).isOpen) : ((bool?)null)) == true)
			{
				((MenuWindow)GUIManager.instance.endScreen).Close();
			}
		}
		GameOverHandler val = Object.FindFirstObjectByType<GameOverHandler>();
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: GameOverHandler not found.");
			return;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Forcing all players to close end screen...");
		val.ForceEveryPlayerDoneWithEndScreen();
		shouldAutoRestart = autoRestart;
		((BaseUnityPlugin)this).Logger.LogInfo((object)(autoRestart ? "Quick Restart: Returning to airport, will auto-restart." : "Quick Restart: Returning to airport."));
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		PublishModPresence();
		restartInProgress = false;
		if (((Scene)(ref scene)).name == "Airport" && shouldAutoRestart)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Airport scene loaded — waiting until everyone is ready, then boarding.");
			((MonoBehaviour)this).StartCoroutine(AirportAutoRestartRoutine());
		}
		else if (((Scene)(ref scene)).name == "Title" && enableMainMenuAutoClick.Value && !hasAutoClickedMainMenuButton)
		{
			hasAutoClickedMainMenuButton = true;
			((MonoBehaviour)this).StartCoroutine(AutoClickMainMenuButton());
		}
	}

	private IEnumerator AirportAutoRestartRoutine()
	{
		shouldAutoRestart = false;
		for (float t = 0f; t < 30f; t += 0.25f)
		{
			int num;
			if (!LoadingScreenHandler.loading)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene)).name == "Airport" && (Object)(object)Character.localCharacter != (Object)null && Character.localCharacter.inAirport)
				{
					num = (((Object)(object)Object.FindFirstObjectByType<AirportCheckInKiosk>() != (Object)null) ? 1 : 0);
					goto IL_009e;
				}
			}
			num = 0;
			goto IL_009e;
			IL_009e:
			if (num != 0)
			{
				break;
			}
			yield return (object)new WaitForSecondsRealtime(0.25f);
		}
		if ((Object)(object)Object.FindFirstObjectByType<AirportCheckInKiosk>() == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Timed out waiting for host airport readiness.");
			yield break;
		}
		if (!IsSoloSession())
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Host ready — waiting up to 10s for other players in airport...");
			for (float t = 0f; t < 10f; t += 0.25f)
			{
				if (AllPlayersReadyInAirport())
				{
					break;
				}
				yield return (object)new WaitForSecondsRealtime(0.25f);
			}
			if (!AllPlayersReadyInAirport())
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Quick Restart: Boarding anyway; still waiting on: " + DescribePlayersNotReadyInAirport()));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: All players ready in airport — boarding.");
			}
		}
		TrySetRandomSeed();
		AirportCheckInKiosk kiosk = Object.FindFirstObjectByType<AirportCheckInKiosk>();
		if ((Object)(object)kiosk == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Kiosk not found after airport wait.");
		}
		else if (useDailySeed)
		{
			yield return WaitAndStartGame(kiosk);
		}
		else
		{
			kiosk.StartGame(Ascents.currentAscent);
		}
	}

	private void TryStartGameFromAirport()
	{
		AirportCheckInKiosk val = Object.FindFirstObjectByType<AirportCheckInKiosk>();
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: No AirportCheckInKiosk found!");
			return;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Starting game from Airport via vanilla kiosk.StartGame.");
		TrySetRandomSeed();
		if (useDailySeed)
		{
			((MonoBehaviour)this).StartCoroutine(WaitAndStartGame(val));
		}
		else
		{
			val.StartGame(Ascents.currentAscent);
		}
	}

	private IEnumerator WaitAndStartGame(AirportCheckInKiosk kiosk)
	{
		yield return (object)new WaitForSeconds(0.5f);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Starting game after property sync.");
		kiosk.StartGame(Ascents.currentAscent);
	}

	private IEnumerator WaitAndStartGameFromAirport()
	{
		yield return (object)new WaitForSeconds(0.5f);
		TryStartGameFromAirport();
	}

	private void SetShouldRandomise(bool value)
	{
		if (PhotonNetwork.CurrentRoom != null)
		{
			Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
			customProperties[(object)"shouldRandomise"] = value;
			PhotonNetwork.CurrentRoom.SetCustomProperties(customProperties, (Hashtable)null, (WebFlags)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Quick Restart: Set shouldRandomise = {value}");
		}
	}

	private void SetNewRandomSeed()
	{
		if (PhotonNetwork.CurrentRoom != null)
		{
			int num = Random.Range(1, 10001);
			Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
			customProperties[(object)"seed"] = num;
			PhotonNetwork.CurrentRoom.SetCustomProperties(customProperties, (Hashtable)null, (WebFlags)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Quick Restart: Set new random seed = {num}");
		}
	}

	private void TrySetRandomSeed()
	{
		if (useRandomSeed)
		{
			SetShouldRandomise(value: true);
			SetNewRandomSeed();
		}
	}

	private void CallInteractCastFinished()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		if (((Scene)(ref activeScene)).name != "Airport")
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: Ascent kiosk is only available in the Airport scene.");
			return;
		}
		Character val = null;
		if (Character.AllCharacters != null && Character.AllCharacters.Count > 0)
		{
			val = ((IEnumerable<Character>)Character.AllCharacters).FirstOrDefault((Func<Character, bool>)((Character c) => (Object)(object)c.refs?.view != (Object)null && c.refs.view.OwnerActorNr == PhotonNetwork.LocalPlayer.ActorNumber));
		}
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: No local character found for kiosk interaction.");
			return;
		}
		AirportCheckInKiosk val2 = Object.FindFirstObjectByType<AirportCheckInKiosk>();
		if ((Object)(object)val2 == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Quick Restart: No AirportCheckInKiosk found.");
			return;
		}
		try
		{
			val2.Interact_CastFinished(val);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Restart: Opened ascent kiosk.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Quick Restart: Error opening ascent kiosk: " + ex.Message));
		}
	}

	private IEnumerator AutoClickMainMenuButton()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"Quick Restart: Waiting {mainMenuClickDelay.Value}s before clicking {mainMenuButtonChoice.Value}");
		yield return (object)new WaitForSeconds(mainMenuClickDelay.Value);
		try
		{
			GameObject obj = GameObject.Find(mainMenuButtonChoice.Value);
			Button button = ((obj != null) ? obj.GetComponent<Button>() : null);
			if ((Object)(object)button != (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Quick Restart: Clicking " + mainMenuButtonChoice.Value));
				((UnityEvent)button.onClick).Invoke();
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Quick Restart: " + mainMenuButtonChoice.Value + " not found"));
			}
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			((BaseUnityPlugin)this).Logger.LogError((object)("Quick Restart: Error auto-clicking: " + ex2.Message));
		}
	}

	private static IEnumerator WaitForModPresence(float timeout)
	{
		if (!(timeout <= 0f) && !AllConnectedPlayersHaveMod())
		{
			float t = 0f;
			while (!AllConnectedPlayersHaveMod() && t < timeout)
			{
				yield return (object)new WaitForSecondsRealtime(0.15f);
				t += 0.15f;
			}
		}
	}

	private static bool AllConnectedPlayersHaveMod()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return false;
		}
		Player[] playerList = PhotonNetwork.PlayerList;
		foreach (Player val in playerList)
		{
			Hashtable customProperties = val.CustomProperties;
			if (customProperties == null || !((Dictionary<object, object>)(object)customProperties).ContainsKey((object)"QR_ModVersion"))
			{
				return false;
			}
		}
		return true;
	}

	private static string DescribeMissingModPlayers()
	{
		if (!PhotonNetwork.InRoom)
		{
			return "not in room";
		}
		List<string> list = new List<string>();
		Player[] playerList = PhotonNetwork.PlayerList;
		foreach (Player val in playerList)
		{
			Hashtable customProperties = val.CustomProperties;
			if (customProperties == null || !((Dictionary<object, object>)(object)customProperties).ContainsKey((object)"QR_ModVersion"))
			{
				list.Add(string.IsNullOrEmpty(val.NickName) ? $"#{val.ActorNumber}" : val.NickName);
			}
		}
		return (list.Count == 0) ? "none" : string.Join(", ", list);
	}

	private static bool AllPlayersReadyInAirport()
	{
		if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
		{
			return (Object)(object)Character.localCharacter != (Object)null && Character.localCharacter.inAirport;
		}
		Player[] playerList = PhotonNetwork.PlayerList;
		foreach (Player val in playerList)
		{
			if (val != null && !val.IsInactive)
			{
				Character playerCharacter = PlayerHandler.GetPlayerCharacter(val);
				if ((Object)(object)playerCharacter == (Object)null || !playerCharacter.inAirport)
				{
					return false;
				}
			}
		}
		return true;
	}

	private static string DescribePlayersNotReadyInAirport()
	{
		if (!PhotonNetwork.InRoom)
		{
			return "not in room";
		}
		List<string> list = new List<string>();
		Player[] playerList = PhotonNetwork.PlayerList;
		foreach (Player val in playerList)
		{
			if (val != null && !val.IsInactive)
			{
				string text = (string.IsNullOrEmpty(val.NickName) ? $"#{val.ActorNumber}" : val.NickName);
				Character playerCharacter = PlayerHandler.GetPlayerCharacter(val);
				if ((Object)(object)playerCharacter == (Object)null)
				{
					list.Add(text + " (no character)");
				}
				else if (!playerCharacter.inAirport)
				{
					list.Add(text + " (not in airport)");
				}
			}
		}
		return (list.Count == 0) ? "none" : string.Join(", ", list);
	}
}