Decompiled source of RambosValheimModGuide v2.0.0

BepInEx/plugins/RambosValheimModGuide.dll

Decompiled a day ago
using System;
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.Bootstrap;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[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 RambosValheimModGuide
{
	[BepInPlugin("rambos.valheim.modguide", "Rambo's Valheim Mod Guide", "2.0.0")]
	public class ModGuide : BaseUnityPlugin
	{
		private class ModInfo
		{
			public string Name;

			public string Guid;

			public string Version;

			public string Description;

			public bool IsSelf;

			public int KeybindCount;
		}

		private class KeyBindInfo
		{
			public string Key;

			public string ModName;

			public string Action;

			public string Section;
		}

		private Rect window = new Rect(70f, 45f, 980f, 700f);

		private bool visible;

		private Vector2 scroll;

		private GUIStyle title;

		private GUIStyle subtitle;

		private GUIStyle tab;

		private GUIStyle tabActive;

		private GUIStyle heading;

		private GUIStyle normal;

		private GUIStyle small;

		private GUIStyle modName;

		private GUIStyle keyStyle;

		private GUIStyle badge;

		private GUIStyle panel;

		private GUIStyle closeStyle;

		private bool stylesReady;

		private int tabIndex;

		private readonly List<ModInfo> mods = new List<ModInfo>();

		private readonly List<KeyBindInfo> keybinds = new List<KeyBindInfo>();

		private readonly Dictionary<string, string> knownDescriptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Epic Loot", "Adds RPG-style magical weapons, armour, enchantments, rarities and loot progression." },
			{ "StarLevelSystem", "Adds progressive enemy star levels and scaling difficulty as you explore and progress." },
			{ "InventorySlots", "Adds extra inventory and quick slots, plus hotbar switching and container restocking." },
			{ "AzuCraftyBoxes", "Lets you craft and manage resources using nearby storage and adds contextual resource actions." },
			{ "MassFarming", "Adds faster farming actions so planting and harvesting large areas takes less time." },
			{ "KeepInventoryOnDeath", "Keeps your inventory when you die instead of requiring a corpse recovery trip." },
			{ "Forsaken Powers Plus Remastered", "Expands and improves the Forsaken Powers system with additional power options." },
			{ "SwmarlyValheimQOL", "Adds a collection of quality-of-life improvements for movement, stamina, building and survival." },
			{ "PlantEverything", "Expands farming and planting options, allowing more plants and cultivation choices." },
			{ "InstantMonsterLootDrop", "Makes monster loot appear immediately instead of requiring the normal pickup/drop delay." },
			{ "TargetPortal", "Improves portal travel with target-based portal linking and easier destination selection." }
		};

		private static readonly string[] HiddenTokens = new string[9] { "jotunn", "jsondotnet", "newtonsoft", "yaml", "bepinexpack", "bepinex", "harmony", "monomod", "0harmony" };

		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Rambo's Valheim Mod Guide 2.0.0 loaded. Press F10 to scan and open the guide.");
		}

		private void EnsureStyles()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Expected O, but got Unknown
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			if (!stylesReady)
			{
				title = MakeStyle(25, (FontStyle)1, Color.white);
				subtitle = MakeStyle(14, (FontStyle)0, new Color(0.78f, 0.8f, 0.84f));
				tab = MakeStyle(15, (FontStyle)1, new Color(0.82f, 0.84f, 0.88f));
				tabActive = MakeStyle(15, (FontStyle)1, new Color(1f, 0.78f, 0.32f));
				heading = MakeStyle(19, (FontStyle)1, new Color(1f, 0.78f, 0.32f));
				normal = MakeStyle(15, (FontStyle)0, new Color(0.91f, 0.92f, 0.94f));
				small = MakeStyle(12, (FontStyle)0, new Color(0.68f, 0.7f, 0.74f));
				modName = MakeStyle(17, (FontStyle)1, Color.white);
				keyStyle = MakeStyle(15, (FontStyle)1, new Color(1f, 0.83f, 0.45f));
				badge = MakeStyle(12, (FontStyle)1, new Color(0.78f, 0.84f, 0.9f));
				panel = new GUIStyle(GUI.skin.box);
				panel.normal.background = MakeTexture(1, 1, new Color(0.055f, 0.065f, 0.075f, 0.96f));
				panel.border = new RectOffset(8, 8, 8, 8);
				panel.padding = new RectOffset(14, 14, 10, 10);
				closeStyle = MakeStyle(14, (FontStyle)1, Color.white);
				stylesReady = true;
			}
		}

		private GUIStyle MakeStyle(int size, FontStyle fontStyle, Color color)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = size,
				fontStyle = fontStyle
			};
			val.normal.textColor = color;
			val.wordWrap = true;
			val.richText = false;
			return val;
		}

		private Texture2D MakeTexture(int width, int height, Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Texture2D val = new Texture2D(width, height);
			val.SetPixel(0, 0, color);
			val.Apply();
			return val;
		}

		private void OnGUI()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_0069: 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)
			//IL_008a: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			EnsureStyles();
			if (Event.current != null && (int)Event.current.type == 4 && (int)Event.current.keyCode == 291)
			{
				visible = !visible;
				if (visible)
				{
					ScanPlugins();
				}
				Event.current.Use();
			}
			if (visible)
			{
				GUI.depth = -100;
				window = GUI.Window(741080, window, new WindowFunction(DrawWindow), GUIContent.none, panel);
			}
		}

		private void ScanPlugins()
		{
			mods.Clear();
			keybinds.Clear();
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				try
				{
					PluginInfo value = pluginInfo.Value;
					if (value == null || value.Metadata == null)
					{
						continue;
					}
					string name = value.Metadata.Name ?? pluginInfo.Key;
					string text = value.Metadata.GUID ?? pluginInfo.Key;
					if (ShouldHide(name, text))
					{
						continue;
					}
					ModInfo modInfo = new ModInfo
					{
						Name = name,
						Guid = text,
						Version = value.Metadata.Version.ToString(),
						Description = FindDescription(name, text),
						IsSelf = text.Equals("rambos.valheim.modguide", StringComparison.OrdinalIgnoreCase)
					};
					if (!modInfo.IsSelf)
					{
						if ((Object)(object)value.Instance != (Object)null)
						{
							ScanConfig(value.Instance.Config, modInfo);
						}
						mods.Add(modInfo);
					}
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogDebug((object)("Mod scan skipped a plugin: " + ex.Message));
				}
			}
			mods.Sort((ModInfo a, ModInfo b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
			keybinds.Sort((KeyBindInfo a, KeyBindInfo b) => string.Compare(a.Key, b.Key, StringComparison.OrdinalIgnoreCase));
		}

		private void ScanConfig(ConfigFile config, ModInfo mod)
		{
			//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_0056: 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)
			if (config == null)
			{
				return;
			}
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item2 in config)
			{
				try
				{
					if (item2.Value == null || item2.Value.SettingType != typeof(KeyboardShortcut))
					{
						continue;
					}
					KeyboardShortcut shortcut = (KeyboardShortcut)item2.Value.BoxedValue;
					if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0)
					{
						string key = FormatShortcut(shortcut);
						string value = ((item2.Value.Description != null) ? item2.Value.Description.Description : "");
						if (string.IsNullOrWhiteSpace(value))
						{
							value = item2.Key.Key;
						}
						KeyBindInfo item = new KeyBindInfo
						{
							Key = key,
							ModName = mod.Name,
							Action = CleanDescription(value),
							Section = item2.Key.Section
						};
						keybinds.Add(item);
						mod.KeybindCount++;
					}
				}
				catch
				{
				}
			}
		}

		private string FormatShortcut(KeyboardShortcut shortcut)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if ((int)modifier != 0)
				{
					list.Add(PrettyKey(modifier));
				}
			}
			list.Add(PrettyKey(((KeyboardShortcut)(ref shortcut)).MainKey));
			return string.Join(" + ", list);
		}

		private unsafe string PrettyKey(KeyCode key)
		{
			string text = ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			text = text.Replace("Alpha", "");
			text = text.Replace("Keypad", "Num");
			text = text.Replace("Left", "L-");
			text = text.Replace("Right", "R-");
			return text switch
			{
				"BackQuote" => "`", 
				"Mouse0" => "Mouse1", 
				"Mouse1" => "Mouse2", 
				"Mouse2" => "Mouse3", 
				_ => text, 
			};
		}

		private string FindDescription(string name, string guid)
		{
			foreach (KeyValuePair<string, string> knownDescription in knownDescriptions)
			{
				if (name.IndexOf(knownDescription.Key, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return knownDescription.Value;
				}
			}
			return "Gameplay or quality-of-life plugin detected in your current BepInEx installation.";
		}

		private bool ShouldHide(string name, string guid)
		{
			string text = (name + " " + guid).ToLowerInvariant();
			string[] hiddenTokens = HiddenTokens;
			foreach (string value in hiddenTokens)
			{
				if (text.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private string CleanDescription(string value)
		{
			value = (value ?? "").Replace("\r", " ").Replace("\n", " ").Trim();
			while (value.Contains("  "))
			{
				value = value.Replace("  ", " ");
			}
			return value;
		}

		private void DrawWindow(int id)
		{
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("RAMBO'S VALHEIM MOD GUIDE", title, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("X", closeStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(34f),
				GUILayout.Height(30f)
			}))
			{
				visible = false;
			}
			GUILayout.EndHorizontal();
			GUILayout.Label("Automatic scan of loaded BepInEx plugins • F10 to close", subtitle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawTab("MODS", 0);
			DrawTab("KEYBINDS", 1);
			DrawTab("CONFLICTS", 2);
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Rescan", tab, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(80f),
				GUILayout.Height(30f)
			}))
			{
				ScanPlugins();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
			scroll = GUILayout.BeginScrollView(scroll, false, true, Array.Empty<GUILayoutOption>());
			if (tabIndex == 0)
			{
				DrawMods();
			}
			else if (tabIndex == 1)
			{
				DrawKeybinds();
			}
			else
			{
				DrawConflicts();
			}
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 34f));
		}

		private void DrawTab(string text, int index)
		{
			if (GUILayout.Button(text, (index == tabIndex) ? tabActive : tab, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(115f),
				GUILayout.Height(30f)
			}))
			{
				tabIndex = index;
			}
		}

		private void DrawMods()
		{
			GUILayout.Label("GAMEPLAY & PLAYER MODS", heading, Array.Empty<GUILayoutOption>());
			GUILayout.Label(mods.Count + " user-facing mods detected. Framework/dependency plugins are hidden automatically.", small, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			foreach (ModInfo mod in mods)
			{
				GUILayout.BeginVertical(panel, Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label(mod.Name, modName, Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				GUILayout.Label("v" + mod.Version, badge, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
				GUILayout.EndHorizontal();
				GUILayout.Label(mod.Description, normal, Array.Empty<GUILayoutOption>());
				if (mod.KeybindCount > 0)
				{
					GUILayout.Label(mod.KeybindCount + " keybind" + ((mod.KeybindCount == 1) ? "" : "s") + " detected — see KEYBINDS", keyStyle, Array.Empty<GUILayoutOption>());
				}
				GUILayout.EndVertical();
				GUILayout.Space(7f);
			}
			if (mods.Count == 0)
			{
				GUILayout.Label("No user-facing plugins were detected yet. Press Rescan after the game has finished loading.", normal, Array.Empty<GUILayoutOption>());
			}
		}

		private void DrawKeybinds()
		{
			GUILayout.Label("DETECTED KEYBINDS", heading, Array.Empty<GUILayoutOption>());
			GUILayout.Label(keybinds.Count + " configurable keyboard shortcut" + ((keybinds.Count == 1) ? "" : "s") + " detected.", small, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			if (keybinds.Count == 0)
			{
				GUILayout.Label("No BepInEx KeyboardShortcut settings were detected. Some mods use hard-coded keys and cannot be discovered automatically.", normal, Array.Empty<GUILayoutOption>());
				return;
			}
			string text = null;
			foreach (KeyBindInfo keybind in keybinds)
			{
				if (text != null && text != keybind.Key)
				{
					GUILayout.Space(3f);
				}
				GUILayout.BeginVertical(panel, Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label(keybind.Key, keyStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(190f) });
				GUILayout.Label(keybind.ModName, modName, Array.Empty<GUILayoutOption>());
				GUILayout.EndHorizontal();
				GUILayout.Label(keybind.Action, normal, Array.Empty<GUILayoutOption>());
				GUILayout.EndVertical();
				GUILayout.Space(6f);
				text = keybind.Key;
			}
		}

		private void DrawConflicts()
		{
			GUILayout.Label("KEY CONFLICTS / SHARED KEYS", heading, Array.Empty<GUILayoutOption>());
			List<IGrouping<string, KeyBindInfo>> list = (from g in keybinds.GroupBy<KeyBindInfo, string>((KeyBindInfo x) => x.Key, StringComparer.OrdinalIgnoreCase)
				where g.Count() > 1
				select g).ToList();
			if (list.Count == 0)
			{
				GUILayout.Label("No shared configurable keybinds detected.", normal, Array.Empty<GUILayoutOption>());
				return;
			}
			GUILayout.Label(list.Count + " shared key" + ((list.Count == 1) ? "" : "s") + " detected. Shared keys are not necessarily a problem if their actions are contextual.", small, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			foreach (IGrouping<string, KeyBindInfo> item in list)
			{
				GUILayout.BeginVertical(panel, Array.Empty<GUILayoutOption>());
				GUILayout.Label(item.Key, keyStyle, Array.Empty<GUILayoutOption>());
				foreach (KeyBindInfo item2 in item)
				{
					GUILayout.Label("• " + item2.ModName + " — " + item2.Action, normal, Array.Empty<GUILayoutOption>());
				}
				GUILayout.EndVertical();
				GUILayout.Space(7f);
			}
		}
	}
}