Decompiled source of AutoWorldStart v1.1.8

AutoWorldStart/AutoWorldStart.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.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 Hunter9732ru.AutoWorldStart
{
	[BepInPlugin("hunter9732ru.autoworldstart", "AutoWorldStart-1.1.8", "1.1.8")]
	[BepInIncompatibility("com.github.abearcodes.valheim.simpleautogamestart")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private static Plugin instance;

		private Harmony harmony;

		private ConfigEntry<bool> skipIntroVideo;

		private ConfigEntry<bool> pauseAfterLoad;

		private ConfigEntry<float> pauseInputWindow;

		private static readonly MethodInfo CanPauseMethod = typeof(Game).GetMethod("CanPause", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		private bool pausePending;

		private bool autoPauseOwned;

		private DateTime resumeInputBaseline;

		private DateTime pendingInputBaseline;

		private GameObject hiddenWorldPanel;

		private Camera hiddenMenuCamera;

		private int originalCullingMask;

		private CameraClearFlags originalClearFlags;

		private Color originalBackground;

		private FejdStartup hiddenStartup;

		private float restoreMenuAt;

		private static readonly FieldInfo StartingWorld = typeof(FejdStartup).GetField("m_startingWorld", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private float pauseDeadline;

		private float nextPauseCheck;

		private float pauseReadyAt = -1f;

		private ConfigEntry<bool> autoEnabled;

		private ConfigEntry<string> worldName;

		private ConfigEntry<string> playerName;

		private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly FieldInfo Profiles = typeof(FejdStartup).GetField("m_profiles", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo ProfileIndex = typeof(FejdStartup).GetField("m_profileIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo SelectedWorld = typeof(FejdStartup).GetField("m_world", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo QueuedJoin = typeof(FejdStartup).GetField("m_queuedJoinServer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private bool finished;

		private bool worldAttempted;

		private ConfigEntry<KeyboardShortcut> togglePauseKey;

		private ConfigEntry<KeyboardShortcut> toggleAutoLoadKey;

		private float deadline;

		private void Awake()
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			instance = this;
			skipIntroVideo = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoWorldStart", "SkipIntroVideo", true, "Skip the startup video before the main menu. Does not skip loading or in-world cinematics. / Пропускать видео перед главным меню.");
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(PlatformPrefs), "GetBool", new Type[2]
				{
					typeof(string),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo == null)
				{
					throw new MissingMethodException("PlatformPrefs.GetBool(string, bool)");
				}
				harmony = new Harmony("hunter9732ru.autoworldstart.intro");
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "IntroPreferencePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Intro skip unavailable; automatic world loading remains enabled: " + ex.Message));
			}
			pauseAfterLoad = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoWorldStart", "PauseAfterLoad", true, "After entry, silently pause only if no input occurs during PauseInputWindowSeconds. / После входа пауза без Esc, если за время PauseInputWindowSeconds не было ввода.");
			pauseInputWindow = ((BaseUnityPlugin)this).Config.Bind<float>("AutoWorldStart", "PauseInputWindowSeconds", 1f, new ConfigDescription("Seconds after player/HUD readiness during which input cancels the pending pause. Applied on the next entry. / Сколько секунд после готовности персонажа ввод отменяет будущую паузу. По умолчанию 1; изменение действует при следующем входе.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
			string text = Path.Combine(Paths.ConfigPath, "com.github.abearcodes.valheim.simpleautogamestart.cfg");
			bool flag = true;
			string text2 = "";
			string text3 = "";
			if (File.Exists(text))
			{
				try
				{
					ConfigFile val = new ConfigFile(text, false)
					{
						SaveOnConfigSet = false
					};
					flag = val.Bind<bool>("SimpleAutoGameStart", "Enabled", true, (ConfigDescription)null).Value;
					text2 = val.Bind<string>("SimpleAutoGameStart", "WorldName", "", (ConfigDescription)null).Value;
					text3 = val.Bind<string>("SimpleAutoGameStart", "PlayerName", "", (ConfigDescription)null).Value;
				}
				catch (Exception ex2)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Cannot read old settings: " + ex2.Message));
				}
			}
			autoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoWorldStart", "Enabled", flag, "Automatically load the named local world once when Valheim starts.");
			worldName = ((BaseUnityPlugin)this).Config.Bind<string>("AutoWorldStart", "WorldName", text2, "Existing world display name, exactly as shown in the game. Never creates a world.");
			playerName = ((BaseUnityPlugin)this).Config.Bind<string>("AutoWorldStart", "PlayerName", text3, "Existing character name, exactly as shown in the game.");
			togglePauseKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "TogglePauseAfterLoad", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Toggle automatic pause AFTER loading; does not open or close Esc. / Переключатель паузы после загрузки.");
			toggleAutoLoadKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "ToggleAutoLoad", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Toggle automatic world loading. Saved for next launch; in the initial menu can resume a cancelled attempt. / Переключатель автозагрузки мира.");
			ScheduleAutoLoad();
		}

		private void ScheduleAutoLoad()
		{
			((MonoBehaviour)this).CancelInvoke("TryStart");
			if (!autoEnabled.Value || worldAttempted || (Object)(object)Player.m_localPlayer != (Object)null)
			{
				finished = true;
				return;
			}
			finished = false;
			if (string.IsNullOrWhiteSpace(worldName.Value) || string.IsNullOrWhiteSpace(playerName.Value))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Set WorldName and PlayerName in the config. Automatic start skipped.");
				finished = true;
			}
			else
			{
				deadline = Time.realtimeSinceStartup + 180f;
				((MonoBehaviour)this).InvokeRepeating("TryStart", 0.1f, 0.5f);
			}
		}

		private void Finish()
		{
			finished = true;
			((MonoBehaviour)this).CancelInvoke("TryStart");
			if (!worldAttempted)
			{
				RestoreWorldPanel();
			}
		}

		private static bool Same(string a, string b)
		{
			return string.Equals((a ?? "").Trim(), (b ?? "").Trim(), StringComparison.OrdinalIgnoreCase);
		}

		private void TryStart()
		{
			if (finished)
			{
				return;
			}
			if (!autoEnabled.Value)
			{
				Finish();
				return;
			}
			try
			{
				StartFromMenu();
			}
			catch (Exception ex)
			{
				Finish();
				pausePending = false;
				RestoreWorldPanel();
				((BaseUnityPlugin)this).Logger.LogError((object)("Automatic start stopped; use the normal menu. " + ex));
			}
		}

		private void StartFromMenu()
		{
			if (Time.realtimeSinceStartup > deadline)
			{
				Finish();
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Main menu was not ready within 180 seconds. Automatic start skipped.");
				return;
			}
			FejdStartup val = FejdStartup.instance;
			if ((Object)(object)val == (Object)null || ((Object)(object)val.m_loading != (Object)null && val.m_loading.activeInHierarchy) || (Object)(object)val.m_menuList == (Object)null || !val.m_menuList.activeInHierarchy)
			{
				return;
			}
			if (Profiles == null || ProfileIndex == null || SelectedWorld == null)
			{
				throw new MissingFieldException("FejdStartup selection fields changed.");
			}
			if (!(Profiles.GetValue(val) is List<PlayerProfile> list))
			{
				return;
			}
			if (QueuedJoin != null)
			{
				object value = QueuedJoin.GetValue(val);
				PropertyInfo propertyInfo = value?.GetType().GetProperty("IsValid");
				if (propertyInfo != null && (bool)propertyInfo.GetValue(value, null))
				{
					Finish();
					((BaseUnityPlugin)this).Logger.LogInfo((object)"A server connection is queued; local automatic start skipped.");
					return;
				}
			}
			List<World> worldList = SaveSystem.GetWorldList();
			if (worldList == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = -1;
			World val2 = null;
			string b = worldName.Value.Trim();
			string b2 = playerName.Value.Trim();
			for (int i = 0; i < worldList.Count; i++)
			{
				World val3 = worldList[i];
				if (Same(val3.m_worldName, b) || Same(val3.m_name, b))
				{
					num++;
					val2 = val3;
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				if (Same(list[j].GetName(), b2))
				{
					num2++;
					num3 = j;
				}
			}
			if (num != 1 || num2 != 1)
			{
				Finish();
				((BaseUnityPlugin)this).Logger.LogError((object)("Automatic start needs one matching world and character. World matches: " + num + "; character matches: " + num2 + "."));
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Available worlds: " + string.Join(" | ", worldList.Select((World w) => w.m_worldName).ToArray())));
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Available characters: " + string.Join(" | ", list.Select((PlayerProfile p) => p.GetName()).ToArray())));
				return;
			}
			worldAttempted = true;
			Finish();
			ProfileIndex.SetValue(val, num3);
			HideMenuBackground(val);
			val.OnCharacterStart();
			SelectedWorld.SetValue(val, val2);
			if ((Object)(object)val.m_openServerToggle != (Object)null)
			{
				val.m_openServerToggle.isOn = false;
			}
			if ((Object)(object)val.m_publicServerToggle != (Object)null)
			{
				val.m_publicServerToggle.isOn = false;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Starting world '" + val2.m_worldName + "' with character '" + list[num3].GetName() + "'."));
			val.OnWorldStart();
			if (StartingWorld != null && (bool)StartingWorld.GetValue(val) && (Object)(object)val.m_startGamePanel != (Object)null)
			{
				hiddenWorldPanel = val.m_startGamePanel;
				hiddenStartup = val;
				restoreMenuAt = Time.realtimeSinceStartup + 20f;
				hiddenWorldPanel.SetActive(false);
				nextPauseCheck = 0f;
				pausePending = pauseAfterLoad.Value;
				pauseDeadline = Time.realtimeSinceStartup + 600f;
				pauseReadyAt = -1f;
			}
			else
			{
				RestoreWorldPanel();
				pausePending = false;
			}
		}

		private void Update()
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (((Object)(object)hiddenWorldPanel != (Object)null || (Object)(object)hiddenMenuCamera != (Object)null) && ((Object)(object)hiddenStartup == (Object)null || Time.realtimeSinceStartup >= restoreMenuAt))
			{
				RestoreWorldPanel();
			}
			if (!finished && !worldAttempted && autoEnabled.Value && (Object)(object)hiddenMenuCamera == (Object)null && (Object)(object)Player.m_localPlayer == (Object)null && (Object)(object)FejdStartup.instance != (Object)null)
			{
				HideMenuBackground(FejdStartup.instance);
			}
			if (autoPauseOwned)
			{
				UpdateAutoPause();
			}
			KeyboardShortcut value = togglePauseKey.Value;
			bool flag = ((KeyboardShortcut)(ref value)).IsDown();
			value = toggleAutoLoadKey.Value;
			bool flag2 = ((KeyboardShortcut)(ref value)).IsDown();
			if ((flag || flag2) && !TypingInField())
			{
				if (flag)
				{
					pauseAfterLoad.Value = !pauseAfterLoad.Value;
					SaveSettings();
					Notify("Pause after load / Пауза после загрузки: " + (pauseAfterLoad.Value ? "ON / ВКЛ" : "OFF / ВЫКЛ"));
				}
				if (flag2)
				{
					autoEnabled.Value = !autoEnabled.Value;
					SaveSettings();
					if (!autoEnabled.Value)
					{
						Finish();
					}
					else if (!worldAttempted && (Object)(object)FejdStartup.instance != (Object)null && (Object)(object)Player.m_localPlayer == (Object)null)
					{
						ScheduleAutoLoad();
					}
					Notify("Automatic world load / Автозагрузка: " + (autoEnabled.Value ? "ON / ВКЛ" : "OFF / ВЫКЛ"));
				}
			}
			if (!pausePending)
			{
				return;
			}
			if (!pauseAfterLoad.Value || Time.realtimeSinceStartup > pauseDeadline)
			{
				pausePending = false;
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (pauseReadyAt >= 0f)
			{
				if (HasInputSince(pendingInputBaseline))
				{
					pausePending = false;
					return;
				}
				if (realtimeSinceStartup < pauseReadyAt)
				{
					return;
				}
			}
			if (realtimeSinceStartup < nextPauseCheck)
			{
				return;
			}
			nextPauseCheck = realtimeSinceStartup + 0.1f;
			try
			{
				Player localPlayer = Player.m_localPlayer;
				Menu val = Menu.instance;
				if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null || (Object)(object)Hud.instance == (Object)null || !Hud.instance.IsVisible() || ((Character)localPlayer).IsTeleporting() || ((Character)localPlayer).InCutscene() || ((Character)localPlayer).IsDead())
				{
					pauseReadyAt = -1f;
				}
				else if (pauseReadyAt < 0f)
				{
					float num = pauseInputWindow.Value;
					if (float.IsNaN(num) || float.IsInfinity(num))
					{
						num = 1f;
					}
					num = Math.Max(0.1f, Math.Min(30f, num));
					pauseReadyAt = realtimeSinceStartup + num;
					pendingInputBaseline = ((ZInput.instance == null) ? DateTime.MinValue : ZInput.instance.GetLastInputTimer());
					if (HasInputSince(pendingInputBaseline))
					{
						pausePending = false;
					}
				}
				else if (!(Time.realtimeSinceStartup < pauseReadyAt))
				{
					pausePending = false;
					if (!Menu.IsVisible() && CanPauseMethod != null && (bool)CanPauseMethod.Invoke(null, null) && !Game.IsPaused())
					{
						Game.Pause();
						autoPauseOwned = true;
						resumeInputBaseline = ((ZInput.instance == null) ? DateTime.MinValue : ZInput.instance.GetLastInputTimer());
					}
				}
			}
			catch (Exception ex)
			{
				pausePending = false;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Cannot pause after loading: " + ex.Message));
			}
		}

		private void HideMenuBackground(FejdStartup startup)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)hiddenMenuCamera != (Object)null))
			{
				Camera val = (((Object)(object)startup.m_mainCamera == (Object)null) ? null : startup.m_mainCamera.GetComponent<Camera>());
				if (!((Object)(object)val == (Object)null))
				{
					hiddenMenuCamera = val;
					hiddenStartup = startup;
					restoreMenuAt = deadline;
					originalCullingMask = val.cullingMask;
					originalClearFlags = val.clearFlags;
					originalBackground = val.backgroundColor;
					val.backgroundColor = Color.black;
					val.clearFlags = (CameraClearFlags)2;
					int num = LayerMask.NameToLayer("UI");
					val.cullingMask = ((num < 0) ? originalCullingMask : (originalCullingMask & (1 << num)));
				}
			}
		}

		private void RestoreWorldPanel()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hiddenMenuCamera != (Object)null)
			{
				hiddenMenuCamera.cullingMask = originalCullingMask;
				hiddenMenuCamera.clearFlags = originalClearFlags;
				hiddenMenuCamera.backgroundColor = originalBackground;
			}
			hiddenMenuCamera = null;
			if ((Object)(object)hiddenWorldPanel != (Object)null)
			{
				hiddenWorldPanel.SetActive(true);
			}
			hiddenWorldPanel = null;
			hiddenStartup = null;
		}

		private void UpdateAutoPause()
		{
			if (Menu.IsVisible())
			{
				autoPauseOwned = false;
			}
			else if ((Object)(object)Player.m_localPlayer == (Object)null || !pauseAfterLoad.Value || !Game.IsPaused())
			{
				ReleaseAutoPause();
			}
			else if (HasInputSince(resumeInputBaseline))
			{
				ReleaseAutoPause();
			}
		}

		private static bool HasInputSince(DateTime baseline)
		{
			//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)
			ZInput val = ZInput.instance;
			if (!Input.anyKeyDown && (val == null || !(val.GetLastInputTimer() > baseline)))
			{
				Vector2 mouseDelta = ZInput.GetMouseDelta();
				if (!(((Vector2)(ref mouseDelta)).sqrMagnitude > 0f))
				{
					return ZInput.GetMouseScrollWheel() != 0f;
				}
			}
			return true;
		}

		private void ReleaseAutoPause()
		{
			if (autoPauseOwned)
			{
				autoPauseOwned = false;
				if (!Menu.IsVisible())
				{
					Game.Unpause();
				}
			}
		}

		private static bool TypingInField()
		{
			EventSystem current = EventSystem.current;
			GameObject val = (((Object)(object)current == (Object)null) ? null : current.currentSelectedGameObject);
			if ((Object)(object)val != (Object)null)
			{
				if (!((Object)(object)val.GetComponent<InputField>() != (Object)null))
				{
					return (Object)(object)val.GetComponent<TMP_InputField>() != (Object)null;
				}
				return true;
			}
			return false;
		}

		private void SaveSettings()
		{
			if (!((BaseUnityPlugin)this).Config.SaveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.Save();
			}
		}

		private void Notify(string text)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)text);
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true);
			}
		}

		private static void IntroPreferencePostfix(string __0, ref bool __result)
		{
			if (__0 == "SkipIntroCinematic" && (Object)(object)instance != (Object)null && instance.skipIntroVideo != null && instance.skipIntroVideo.Value)
			{
				__result = true;
			}
		}

		private void OnDestroy()
		{
			((MonoBehaviour)this).CancelInvoke("TryStart");
			ReleaseAutoPause();
			RestoreWorldPanel();
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
}