using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace HostRestartFix;
[BepInPlugin("net.vanilla.hostrestartfix", "HostRestartFix", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
private class DebugLogPatch
{
private static bool betaSaveDataDetected;
private static bool hostStartDetected;
private static void Prefix(object message)
{
if (message != null)
{
string text = message.ToString();
if (text.Contains("host"))
{
logger.LogInfo((object)("Host-related message detected: '" + text + "'"));
}
if (text.Contains("Has beta save data"))
{
logger.LogInfo((object)("Beta save data message detected: '" + text + "'"));
betaSaveDataDetected = true;
CheckBothConditions();
}
if (text.Contains("[Info : Unity Log] started host!") || text.Contains("started host") || (text.Contains("host") && text.Contains("start")))
{
logger.LogInfo((object)("Host start message detected: '" + text + "'"));
logger.LogInfo((object)$"Current flags - hasBeenForceQuit: {hasBeenForceQuit}, firstHostDetected: {firstHostDetected}, betaSaveDataDetected: {betaSaveDataDetected}");
hostStartDetected = true;
CheckBothConditions();
}
}
}
private static void CheckBothConditions()
{
logger.LogInfo((object)$"Checking both conditions - hostStartDetected: {hostStartDetected}, betaSaveDataDetected: {betaSaveDataDetected}, hasBeenForceQuit: {hasBeenForceQuit}");
if (!hasBeenForceQuit && hostStartDetected && betaSaveDataDetected)
{
logger.LogInfo((object)"Both conditions met! Will force quit to menu in 10 seconds.");
firstHostDetected = true;
if (!((Object)(object)Instance == (Object)null))
{
try
{
logger.LogInfo((object)"Starting ForceQuitToMenu coroutine");
((MonoBehaviour)Instance).StartCoroutine(ForceQuitToMenu());
logger.LogInfo((object)"Coroutine started successfully");
return;
}
catch (Exception ex)
{
logger.LogError((object)("Failed to start coroutine: " + ex.Message));
logger.LogError((object)ex.StackTrace);
hasBeenForceQuit = true;
ForceReturnToMainMenu();
return;
}
}
logger.LogError((object)"Plugin Instance is null! Cannot start coroutine!");
}
else
{
logger.LogInfo((object)$"Not all conditions met: hostStartDetected={hostStartDetected}, betaSaveDataDetected={betaSaveDataDetected}, hasBeenForceQuit={hasBeenForceQuit}");
}
}
}
[CompilerGenerated]
private sealed class <ForceQuitToMenu>d__13 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
private float <timer>5__1;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ForceQuitToMenu>d__13(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Expected O, but got Unknown
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Expected O, but got Unknown
//IL_021a: Unknown result type (might be due to invalid IL or missing references)
//IL_0224: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
logger.LogInfo((object)"ForceQuitToMenu coroutine started");
if ((Object)(object)messageObject != (Object)null)
{
messageObject.SetActive(true);
if ((Object)(object)messageText != (Object)null)
{
((TMP_Text)messageText).text = "The Mods have Pre-loaded. Returning to menu in 10 seconds.\nPlease re-host the game for proper weather loading.";
}
logger.LogInfo((object)"Message displayed");
}
else
{
logger.LogError((object)"messageObject is null!");
}
<timer>5__1 = 10f;
goto IL_0145;
case 1:
<>1__state = -1;
<timer>5__1--;
goto IL_0145;
case 2:
<>1__state = -1;
logger.LogInfo((object)"Showing completion message");
if ((Object)(object)messageObject != (Object)null && (Object)(object)messageText != (Object)null)
{
messageObject.SetActive(true);
((TMP_Text)messageText).text = "Please start hosting again for proper weather loading.";
<>2__current = (object)new WaitForSeconds(5f);
<>1__state = 3;
return true;
}
break;
case 3:
{
<>1__state = -1;
messageObject.SetActive(false);
break;
}
IL_0145:
if (<timer>5__1 > 0f)
{
if ((Object)(object)messageText != (Object)null)
{
((TMP_Text)messageText).text = $"The Mods have Pre-loaded. Returning to menu in {<timer>5__1:0} seconds.\nPlease re-host the game for proper weather loading.";
}
logger.LogInfo((object)$"Timer: {<timer>5__1}");
<>2__current = (object)new WaitForSeconds(1f);
<>1__state = 1;
return true;
}
logger.LogInfo((object)"Timer completed, setting hasBeenForceQuit=true");
hasBeenForceQuit = true;
if ((Object)(object)messageObject != (Object)null)
{
messageObject.SetActive(false);
}
logger.LogInfo((object)"Calling ForceReturnToMainMenu");
ForceReturnToMainMenu();
<>2__current = (object)new WaitForSeconds(2f);
<>1__state = 2;
return true;
}
logger.LogInfo((object)"ForceQuitToMenu coroutine completed successfully");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
internal static ManualLogSource logger;
private static bool firstHostDetected;
private static bool hasBeenForceQuit;
private static GameObject messageObject;
private static TextMeshProUGUI messageText;
internal static Plugin Instance;
internal static ConfigEntry<Key> RestartKey;
private static bool keyPressedNow;
private void Awake()
{
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Expected O, but got Unknown
//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
//IL_02bc: Expected O, but got Unknown
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Expected O, but got Unknown
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Expected O, but got Unknown
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Expected O, but got Unknown
//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0213: Unknown result type (might be due to invalid IL or missing references)
//IL_0252: Unknown result type (might be due to invalid IL or missing references)
logger = ((BaseUnityPlugin)this).Logger;
logger.LogInfo((object)"Plugin net.vanilla.hostrestartfix is loaded!");
Instance = this;
logger.LogInfo((object)"Plugin instance set");
RestartKey = ((BaseUnityPlugin)this).Config.Bind<Key>("General", "RestartKey", (Key)32, "This key, when pressed in combination with Ctrl+Shift+Alt, will force return to main menu (useful if mods break)");
try
{
Harmony val = new Harmony("net.vanilla.hostrestartfix");
MethodInfo methodInfo = AccessTools.Method(typeof(Debug), "Log", new Type[1] { typeof(object) }, (Type[])null);
if (methodInfo == null)
{
logger.LogError((object)"Failed to find Debug.Log method to patch!");
return;
}
MethodInfo methodInfo2 = AccessTools.Method(typeof(DebugLogPatch), "Prefix", (Type[])null, (Type[])null);
if (methodInfo2 == null)
{
logger.LogError((object)"Failed to find prefix method for patching!");
return;
}
val.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
logger.LogInfo((object)"Debug.Log patch applied successfully");
val.PatchAll(Assembly.GetExecutingAssembly());
logger.LogInfo((object)"All patches applied successfully");
}
catch (Exception ex)
{
logger.LogError((object)("Failed to apply Harmony patch: " + ex.Message));
logger.LogError((object)ex.StackTrace);
return;
}
try
{
GameObject val2 = new GameObject("RestartFixMessageCanvas");
Object.DontDestroyOnLoad((Object)(object)val2);
Canvas val3 = val2.AddComponent<Canvas>();
val3.renderMode = (RenderMode)0;
val3.sortingOrder = 10000;
messageObject = new GameObject("RestartFixMessage");
messageObject.transform.SetParent(((Component)val3).transform, false);
RectTransform val4 = messageObject.AddComponent<RectTransform>();
val4.anchorMin = new Vector2(0.5f, 0.5f);
val4.anchorMax = new Vector2(0.5f, 0.5f);
val4.pivot = new Vector2(0.5f, 0.5f);
val4.sizeDelta = new Vector2(800f, 100f);
messageText = messageObject.AddComponent<TextMeshProUGUI>();
((TMP_Text)messageText).fontSize = 24f;
((TMP_Text)messageText).alignment = (TextAlignmentOptions)514;
((Graphic)messageText).color = Color.red;
((TMP_Text)messageText).text = "";
messageObject.SetActive(false);
logger.LogInfo((object)"UI components created successfully");
}
catch (Exception ex2)
{
logger.LogError((object)("Error creating UI: " + ex2.Message));
}
try
{
GameObject val5 = new GameObject("ReHosterKeyHandler");
val5.AddComponent<KeybindHandlerBehaviour>();
Object.DontDestroyOnLoad((Object)(object)val5);
logger.LogInfo((object)"Keybind handler created successfully");
}
catch (Exception ex3)
{
logger.LogError((object)("Error creating keybind handler: " + ex3.Message));
}
hasBeenForceQuit = false;
firstHostDetected = false;
logger.LogInfo((object)("Flags reset: hasBeenForceQuit=" + hasBeenForceQuit));
}
private void Update()
{
if (Keyboard.current != null)
{
CheckForceRestartKeybind();
}
}
public static void CheckForceRestartKeybind()
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
if (Keyboard.current == null)
{
return;
}
if (Keyboard.current.ctrlKey.isPressed && Keyboard.current.altKey.isPressed && Keyboard.current.shiftKey.isPressed)
{
KeyControl val = ((IEnumerable<KeyControl>)(object)Keyboard.current.allKeys).FirstOrDefault((Func<KeyControl, bool>)((KeyControl key) => key.keyCode == RestartKey.Value));
if (val != null && ((ButtonControl)val).isPressed)
{
if (!keyPressedNow)
{
logger.LogInfo((object)"Force restart keybind pressed!");
ForceReturnToMainMenu();
}
keyPressedNow = true;
}
else
{
keyPressedNow = false;
}
}
else
{
keyPressedNow = false;
}
}
public static void ForceReturnToMainMenu()
{
logger.LogInfo((object)"ForceReturnToMainMenu called");
if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsConnectedClient)
{
try
{
GameNetworkManager instance = GameNetworkManager.Instance;
if (instance != null)
{
instance.Disconnect();
}
logger.LogInfo((object)"Attempted clean disconnect through GameNetworkManager");
}
catch (Exception ex)
{
logger.LogError((object)("Error during disconnect: " + ex.Message));
}
try
{
NetworkManager.Singleton.Shutdown(false);
logger.LogInfo((object)"Force shutdown NetworkManager");
}
catch (Exception ex2)
{
logger.LogError((object)("Error during NetworkManager shutdown: " + ex2.Message));
}
}
else
{
logger.LogInfo((object)"Not connected to network or NetworkManager.Singleton is null");
}
if ((Object)(object)GameNetworkManager.Instance != (Object)null)
{
try
{
MethodInfo method = typeof(GameNetworkManager).GetMethod("ResetGameValuesToDefault", BindingFlags.Instance | BindingFlags.NonPublic);
if (method != null)
{
method.Invoke(GameNetworkManager.Instance, new object[0]);
logger.LogInfo((object)"Reset game values to default");
}
else
{
logger.LogError((object)"ResetGameValuesToDefault method not found");
}
}
catch (Exception ex3)
{
logger.LogError((object)("Error resetting game values: " + ex3.Message));
}
}
else
{
logger.LogInfo((object)"GameNetworkManager.Instance is null");
}
try
{
logger.LogInfo((object)"Attempting to load main menu scene by index");
SceneManager.LoadScene(0);
logger.LogInfo((object)"Loaded main menu scene");
}
catch (Exception ex4)
{
logger.LogError((object)("Error loading main menu scene: " + ex4.Message));
try
{
logger.LogInfo((object)"Attempting to load main menu scene by name");
SceneManager.LoadScene("MainMenu");
logger.LogInfo((object)"Loaded main menu scene by name");
}
catch (Exception ex5)
{
logger.LogError((object)("Error loading main menu scene by name: " + ex5.Message));
}
}
}
[IteratorStateMachine(typeof(<ForceQuitToMenu>d__13))]
private static IEnumerator ForceQuitToMenu()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ForceQuitToMenu>d__13(0);
}
}
public class KeybindHandlerBehaviour : MonoBehaviour
{
private void Update()
{
Plugin.CheckForceRestartKeybind();
}
}
[HarmonyPatch]
internal class ReHosterPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(StartOfRound), "Start")]
public static void InGameSetup()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
GameObject val = GameObject.Find("ReHosterKeyHandler");
if ((Object)(object)val == (Object)null)
{
val = new GameObject("ReHosterKeyHandler");
val.AddComponent<KeybindHandlerBehaviour>();
Object.DontDestroyOnLoad((Object)(object)val);
Plugin.logger.LogInfo((object)"Created KeybindHandlerBehaviour in game scene");
}
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "net.vanilla.hostrestartfix";
public const string PLUGIN_NAME = "HostRestartFix";
public const string PLUGIN_VERSION = "1.0.0";
}