Decompiled source of ValheimRadial v1.0.2

ValheimRadial.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Valheim.UI;
using ValheimRadial.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimRadial")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("PerspectiveBroad4501")]
[assembly: AssemblyProduct("ValheimRadial")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.0.2")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ValheimRadial
{
	public class InventoryRowsRadialConfig : ScriptableObject, IRadialConfig
	{
		[SerializeField]
		public Sprite m_icon;

		public string LocalizedName => Localization.instance.Localize("$settings_radial");

		public Sprite Sprite => m_icon;

		public void InitRadialConfig(RadialBase radial)
		{
			List<RadialMenuElement> list = new List<RadialMenuElement>();
			bool flag = ValheimRadialPlugin.InvIncludeEmptySlots.Value.IsOn();
			foreach (ItemData configuredInvItem in GetConfiguredInvItems(flag))
			{
				RadialMenuElement item;
				if (configuredInvItem == null)
				{
					if (!flag)
					{
						continue;
					}
					EmptyElement obj = Object.Instantiate<EmptyElement>(RadialData.SO.EmptyElement);
					obj.Init();
					item = (RadialMenuElement)(object)obj;
				}
				else
				{
					ItemElement obj2 = Object.Instantiate<ItemElement>(RadialData.SO.ItemElement);
					obj2.Init(configuredInvItem);
					((RadialMenuElement)obj2).CloseOnInteract = () => true;
					((RadialMenuElement)obj2).AdvancedCloseOnInteract = null;
					((RadialMenuElement)obj2).SubTitle = ((configuredInvItem.m_gridPos.y == 0) ? configuredInvItem.m_gridPos.x.ToString() : string.Empty);
					item = (RadialMenuElement)(object)obj2;
				}
				list.Add(item);
			}
			if (list.Count == 0)
			{
				RadialData.SO.HotbarGroupConfig.InitRadialConfig(radial);
				radial.CurrentConfig = (IRadialConfig)(object)RadialData.SO.HotbarGroupConfig;
			}
			else
			{
				radial.ConstructRadial(list);
			}
		}

		private static List<ItemData> GetConfiguredInvItems(bool includeEmpty)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return new List<ItemData>();
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			_ = inventory.m_inventory;
			int height = inventory.m_height;
			int width = inventory.m_width;
			int num = Mathf.Clamp(ValheimRadialPlugin.InvRowStart.Value, 0, Math.Max(0, height - 1));
			int num2 = Mathf.Clamp(ValheimRadialPlugin.InvRowCount.Value, 1, Math.Max(1, height - num));
			InventoryRowFilterMode activeFilterMode = PcRadialState.GetActiveFilterMode();
			bool flag = ValheimRadialPlugin.InvFilterEquippedOnly.Value.IsOn();
			HashSet<string> hashSet = InventoryRowFilter.ParseCustomNameList(ValheimRadialPlugin.InvCustomNameFilter.Value);
			if (num == 0 && num2 == 1 && includeEmpty && activeFilterMode == InventoryRowFilterMode.AllItems && !flag && (hashSet == null || hashSet.Count == 0))
			{
				return inventory.GetHotbar(true);
			}
			List<ItemData> list = new List<ItemData>(width * num2);
			for (int i = num; i < num + num2 && i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					ItemData itemAt = inventory.GetItemAt(j, i);
					if (itemAt != null)
					{
						if ((flag && !itemAt.m_equipped) || !InventoryRowFilter.PassesFilter(itemAt, activeFilterMode, hashSet))
						{
							if (includeEmpty)
							{
								list.Add(null);
							}
							continue;
						}
					}
					else if (!includeEmpty)
					{
						continue;
					}
					list.Add(itemAt);
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(Player), "HandleRadialInput")]
	internal static class PlayerHandleRadialInputPatch
	{
		private static void Postfix(Player __instance)
		{
			//IL_0047: 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_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)
			//IL_005d: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)Hud.instance) || !Object.op_Implicit((Object)(object)Hud.instance.m_radialMenu))
			{
				return;
			}
			RadialBase radialMenu = Hud.instance.m_radialMenu;
			KeyboardShortcut value = ValheimRadialPlugin.OpenKey.Value;
			KeyboardShortcut value2 = ValheimRadialPlugin.EmoteKey.Value;
			KeyboardShortcut value3 = ValheimRadialPlugin.CloseKey.Value;
			RadialActivationMode value4 = ValheimRadialPlugin.ActivationMode.Value;
			bool flag = false;
			if (!PcRadialState.IsPcRadialOpen && !radialMenu.m_isClosing && !radialMenu.m_closeQueued)
			{
				bool flag2 = PcRadialState.CanToggleNow();
				bool num = value.IsKeyDown() || (!ZInput.GetButton("JoyAltKeys") && ZInput.GetButtonDown("JoyRadial"));
				bool flag3 = value2.IsKeyDown();
				if ((num || flag3) && flag2)
				{
					PcRadialState.MarkToggle();
					OpenPcRadial(Hud.instance, radialMenu, flag3);
					flag = true;
				}
			}
			if (PcRadialState.IsPcRadialOpen && !flag)
			{
				HandleProfileCycling(radialMenu);
				bool canToggle = PcRadialState.CanToggleNow();
				switch (value4)
				{
				case RadialActivationMode.Toggle:
					HandleToggleModeClose(radialMenu, value, value2, value3, canToggle);
					break;
				case RadialActivationMode.Hold:
					HandleHoldModeClose(radialMenu, value, value2, value3, canToggle);
					break;
				default:
					throw new ArgumentOutOfRangeException();
				}
			}
		}

		private static void HandleProfileCycling(RadialBase radial)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (PcRadialState.CurrentContext != RadialContextKind.Inventory)
			{
				return;
			}
			int num = 0;
			float y = Input.mouseScrollDelta.y;
			if (y > 0.01f)
			{
				num = 1;
			}
			else if (y < -0.01f)
			{
				num = -1;
			}
			if (num == 0)
			{
				if (ZInput.GetButtonDown("JoyDPadRight"))
				{
					num = 1;
				}
				else if (ZInput.GetButtonDown("JoyDPadLeft"))
				{
					num = -1;
				}
			}
			if (num != 0 && PcRadialState.CanCycleProfileNow())
			{
				PcRadialState.StepProfile(num, radial);
			}
		}

		private static void HandleToggleModeClose(RadialBase radial, KeyboardShortcut openKey, KeyboardShortcut emoteKey, KeyboardShortcut closeKey, bool canToggle)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (canToggle && (openKey.IsKeyDown() || emoteKey.IsKeyDown() || closeKey.IsKeyDown() || ZInput.GetButton("Escape") || ZInput.GetButtonUp("JoyRadial")))
			{
				PcRadialState.MarkToggle();
				PcRadialState.MarkExplicitClose(radial);
			}
		}

		private static void HandleHoldModeClose(RadialBase radial, KeyboardShortcut openKey, KeyboardShortcut emoteKey, KeyboardShortcut closeKey, bool canToggle)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			bool flag = openKey.IsKeyHeld() || emoteKey.IsKeyHeld() || ZInput.GetButton("JoyRadial");
			bool flag2 = closeKey.IsKeyDown() || ZInput.GetButton("Escape");
			if ((canToggle || flag2) && !(!flag2 && flag))
			{
				PcRadialState.MarkToggle();
				PcRadialState.MarkExplicitClose(radial);
			}
		}

		private static void OpenPcRadial(Hud hud, RadialBase radial, bool openEmoteWheel)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			radial.m_localPlayerRef = localPlayer;
			radial.ResetAllVariables();
			radial.LoadSettings();
			PcRadialState.HijackCloseDelegates(radial);
			if (!openEmoteWheel)
			{
				InventoryRowsRadialConfig inventoryRowsRadialConfig = ScriptableObject.CreateInstance<InventoryRowsRadialConfig>();
				inventoryRowsRadialConfig.InitRadialConfig(radial);
				radial.CurrentConfig = (IRadialConfig)(object)inventoryRowsRadialConfig;
				Object.Destroy((Object)(object)inventoryRowsRadialConfig);
				PcRadialState.CurrentContext = RadialContextKind.Inventory;
			}
			else
			{
				RadialData.SO.EmoteGroupConfig.InitRadialConfig(radial);
				radial.CurrentConfig = (IRadialConfig)(object)RadialData.SO.EmoteGroupConfig;
				PcRadialState.CurrentContext = RadialContextKind.Emote;
			}
			radial.CanOpen = true;
			radial.ShouldAnimateIn = true;
			radial.Active = true;
			if (RadialData.SO.EnableToggleAnimation)
			{
				RadialArray<RadialMenuElement> elements = radial.m_elements;
				if (elements != null && elements.Count > 0)
				{
					radial.StartAnimatingIn();
					goto IL_00df;
				}
			}
			ElementInfo elementInfo = radial.m_elementInfo;
			elementInfo.Alpha = 1f;
			elementInfo.m_inventoryInfo.SetAlpha(1f);
			elementInfo.Radius = RadialData.SO.ElementInfoRadius;
			goto IL_00df;
			IL_00df:
			PcRadialState.IsPcRadialOpen = true;
		}
	}
	[HarmonyPatch(typeof(RadialBase), "Awake")]
	internal static class ScaleRadialBaseAwakePatch
	{
		private static void Postfix(RadialBase __instance)
		{
			ValheimRadialPlugin.ApplyRadialCustomizations(__instance);
		}
	}
	[HarmonyPatch(typeof(RadialBase), "OnSelectedUpdate")]
	internal static class RadialBaseOnSelectedUpdatePatch
	{
		private static void Postfix(RadialBase __instance)
		{
			//IL_002c: 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)
			if (ValheimRadialPlugin.AudioFeedback.Value.IsOn())
			{
				InventoryGui instance = InventoryGui.instance;
				if (Object.op_Implicit((Object)(object)instance))
				{
					instance.m_moveItemEffects.Create(((Component)instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1);
				}
			}
		}
	}
	[HarmonyPatch(typeof(RadialBase), "Close")]
	internal static class RadialBase_Close_PcRadialPatch
	{
		private static void Postfix(RadialBase __instance)
		{
			if (Object.op_Implicit((Object)(object)Hud.instance) && !((Object)(object)__instance != (Object)(object)Hud.instance.m_radialMenu) && PcRadialState.IsPcRadialOpen)
			{
				PcRadialState.RestoreCloseDelegates(__instance);
			}
		}
	}
	[BepInPlugin("PerspectiveBroad4501.ValheimRadial", "ValheimRadial", "1.0.2")]
	public class ValheimRadialPlugin : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		private class AcceptableShortcuts : AcceptableValueBase
		{
			public AcceptableShortcuts()
				: base(typeof(KeyboardShortcut))
			{
			}

			public override object Clamp(object value)
			{
				return value;
			}

			public override bool IsValid(object value)
			{
				return true;
			}

			public override string ToDescriptionString()
			{
				return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes);
			}
		}

		internal const string ModName = "ValheimRadial";

		internal const string ModVersion = "1.0.2";

		internal const string Author = "PerspectiveBroad4501";

		private const string ModGUID = "PerspectiveBroad4501.ValheimRadial";

		private static string ConfigFileName = "PerspectiveBroad4501.ValheimRadial.cfg";

		private static string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("PerspectiveBroad4501.ValheimRadial");

		public static readonly ManualLogSource ValheimRadialLogger;

		private FileSystemWatcher _watcher;

		private readonly object _reloadLock = new object();

		private DateTime _lastConfigReloadTime;

		private const long RELOAD_DELAY = 10000000L;

		internal static ConfigEntry<RadialActivationMode> ActivationMode;

		internal static ConfigEntry<KeyboardShortcut> OpenKey;

		internal static ConfigEntry<KeyboardShortcut> EmoteKey;

		internal static ConfigEntry<KeyboardShortcut> CloseKey;

		internal static ConfigEntry<Vector3> RadialScale;

		internal static ConfigEntry<Vector3> ElementInfoScale;

		internal static ConfigEntry<Vector3> InventoryInfoScale;

		internal static ConfigEntry<Vector3> TooltipScale;

		internal static ConfigEntry<Vector3> WeightScale;

		internal static ConfigEntry<Vector3> ArmorScale;

		internal static ConfigEntry<Vector2> RadialLocation;

		internal static ConfigEntry<Toggle> AudioFeedback;

		internal static ConfigEntry<int> InvRowStart;

		internal static ConfigEntry<int> InvRowCount;

		internal static ConfigEntry<Toggle> InvIncludeEmptySlots;

		internal static ConfigEntry<InventoryRowFilterMode> InvFilterMode;

		internal static ConfigEntry<Toggle> InvFilterEquippedOnly;

		internal static ConfigEntry<string> InvCustomNameFilter;

		public void Awake()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				ValheimRadialLogger.LogWarning((object)"This mod is meant to only run on the client. Not proceeding with patching or config generation.");
				return;
			}
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			ActivationMode = config("1 - General", "Activation Mode", RadialActivationMode.Toggle, "How the radial behaves for keyboard and controller:\n\nToggle  - Press an open key (or gamepad radial button) once to open, press it again to close.\n          The Close Radial key and Escape also close the wheel.\n\nHold    - Keep an open key (or gamepad radial button) held to keep the radial open.\n          Releasing all open keys closes the wheel. Close Radial / Escape still close instantly.");
			OpenKey = config<KeyboardShortcut>("2 - Keyboard Hotkeys", "Open Hotbar Radial", new KeyboardShortcut((KeyCode)103, Array.Empty<KeyCode>()), new ConfigDescription("Keyboard shortcut that opens the Hotbar radial (your main item wheel).\n\nToggle mode:\n  - Press once to open, press again to close.\n\nHold mode:\n  - The Hotbar radial stays open while this key is held.\n\nNote: Gamepad users can still use the vanilla JoyRadial button.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty<object>()));
			EmoteKey = config<KeyboardShortcut>("2 - Keyboard Hotkeys", "Open Emotes Radial", new KeyboardShortcut((KeyCode)103, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), new ConfigDescription("Keyboard shortcut that opens the Emote radial.\n\nDefault: Alt + G.\n\nToggle mode:\n  - Press once to open the emote wheel, press again to close.\n\nHold mode:\n  - The emote wheel stays open while this key combo is held.\n\nThis does not remove the existing controller bindings; it only adds a PC-friendly shortcut.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty<object>()));
			CloseKey = config<KeyboardShortcut>("2 - Keyboard Hotkeys", "Close Radial", new KeyboardShortcut((KeyCode)27, Array.Empty<KeyCode>()), new ConfigDescription("Dedicated keyboard shortcut to close any currently open radial.\n\nDefaults to Escape. Escape will always close the wheel, even if you change this binding.\nUseful if you prefer to keep the open key purely for opening/toggling.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty<object>()));
			InvRowStart = config("3 - Inventory Radial", "Start Row Index", 0, "Which inventory row to start from when building the Inventory Row radial.\n0 = top row (default hotbar), 1 = second row, 2 = third row, etc.\nValues outside the inventory height will be clamped.");
			InvRowCount = config("3 - Inventory Radial", "Row Count", 1, "How many inventory rows to include in the radial, starting at Start Row Index.\nFor example: Start=0, Count=1 -> vanilla hotbar row only.\nStart=1, Count=1 -> second row only.\nStart=0, Count=3 -> top three rows.\nIf the chosen range exceeds the inventory height, it will be clamped.");
			InvIncludeEmptySlots = config("3 - Inventory Radial", "Include Empty Slots", Toggle.On, "If true, empty inventory slots within the selected rows appear as empty segments in the radial.\nIf false, only actual items are added and the radial will have fewer segments.");
			InvFilterMode = config("3 - Inventory Radial", "Filter Mode", InventoryRowFilterMode.AllItems, "Controls which items from the selected rows are eligible to appear in the radial:\n- AllItems: no type filtering, every item can appear.\n- WeaponsAndTools: only weapons and tool-type items.\n- WeaponsToolsShields: weapons, tools, and shields.\n- ArmorAndUtility: armor, utility, trinkets.\n- ConsumablesOnly: food, potions, and other consumables.\n- CustomNameWhitelist: only items whose internal name matches the Custom Name Filter list.");
			InvFilterEquippedOnly = config("3 - Inventory Radial", "Equipped Only", Toggle.Off, "When enabled, only items that are currently equipped (m_equipped == true) will appear in the radial.\nThis is applied after the type-based Filter Mode.");
			InvCustomNameFilter = config("3 - Inventory Radial", "Custom Name Filter", "", "Used when Filter Mode = CustomNameWhitelist.\nComma-separated list of item identifiers. Each entry may be either:\n- The internal/shared name (m_shared.m_name), e.g. \"$item_sword_iron\"\n- The prefab name (m_dropPrefab.name), e.g. \"SwordIron\"\nExample:\n\"$item_sword_iron,$item_axe_blackmetal,BowFineWood,ShieldBanded\".\nWhitespace around entries is ignored. Case-insensitive comparison.");
			RadialScale = config<Vector3>("4 - Customizations - Scale", "Radial Scale", Vector3.one, "Overall scale of the radial");
			ElementInfoScale = config<Vector3>("4 - Customizations - Scale", "Element Info Scale", Vector3.one, "Scale of the radial elements");
			InventoryInfoScale = config<Vector3>("4 - Customizations - Scale", "Inventory Info Scale", Vector3.one, "Scale of the inventory elements (tooltip, weight & armor)");
			TooltipScale = config<Vector3>("4 - Customizations - Scale", "Tooltip Scale", Vector3.one, "Scale of the radial's tooltip display");
			WeightScale = config<Vector3>("4 - Customizations - Scale", "Weight Scale", Vector3.one, "Scale of the radial's weight display");
			ArmorScale = config<Vector3>("4 - Customizations - Scale", "Armor Scale", Vector3.one, "Scale of the radial's armor display");
			RadialLocation = config<Vector2>("4 - Customizations - Location", "Radial Location", Vector2.zero, "Overall location of the radial");
			RadialLocation.SettingChanged += delegate
			{
				ApplyRadialCustomizations(null, resetLocation: true);
			};
			AudioFeedback = config("4 - Customizations - Audio", "Audio Feedback", Toggle.On, "If on, play audio feedback as if you're clicking a button.");
			foreach (ConfigEntry<Vector3> item in AllEntries())
			{
				item.SettingChanged += delegate
				{
					ApplyRadialCustomizations(null);
				};
			}
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
			((BaseUnityPlugin)this).Config.Save();
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private static IEnumerable<ConfigEntry<Vector3>> AllEntries()
		{
			yield return RadialScale;
			yield return ElementInfoScale;
			yield return InventoryInfoScale;
			yield return TooltipScale;
			yield return WeightScale;
			yield return ArmorScale;
		}

		private void OnDestroy()
		{
			SaveWithRespectToConfigSet();
			_watcher?.Dispose();
			foreach (ConfigEntry<Vector3> item in AllEntries())
			{
				item.SettingChanged -= delegate
				{
					ApplyRadialCustomizations(null);
				};
			}
			RadialLocation.SettingChanged -= delegate
			{
				ApplyRadialCustomizations(null);
			};
		}

		private void SetupWatcher()
		{
			_watcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			_watcher.Changed += ReadConfigValues;
			_watcher.Created += ReadConfigValues;
			_watcher.Renamed += ReadConfigValues;
			_watcher.IncludeSubdirectories = true;
			_watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			_watcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			DateTime now = DateTime.Now;
			if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000)
			{
				return;
			}
			lock (_reloadLock)
			{
				if (!File.Exists(ConfigFileFullPath))
				{
					ValheimRadialLogger.LogWarning((object)"Config file does not exist. Skipping reload.");
					return;
				}
				try
				{
					ValheimRadialLogger.LogDebug((object)"Reloading configuration...");
					SaveWithRespectToConfigSet(reload: true);
					ValheimRadialLogger.LogInfo((object)"Configuration reload complete.");
				}
				catch (Exception ex)
				{
					ValheimRadialLogger.LogError((object)("Error reloading configuration: " + ex.Message));
				}
			}
			_lastConfigReloadTime = now;
		}

		private void SaveWithRespectToConfigSet(bool reload = false)
		{
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			if (reload)
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			((BaseUnityPlugin)this).Config.Save();
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		internal static void ApplyRadialCustomizations(RadialBase __instance, bool resetLocation = false)
		{
			//IL_0028: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_0113: 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 (!Object.op_Implicit((Object)(object)__instance))
			{
				if (!Object.op_Implicit((Object)(object)Hud.instance))
				{
					return;
				}
				__instance = Hud.instance.m_radialMenu;
			}
			if (RadialLocation.Value != Vector2.zero)
			{
				((Component)((Component)__instance).transform).GetComponent<RectTransform>().anchoredPosition = RadialLocation.Value;
			}
			else if (resetLocation)
			{
				((Component)((Component)__instance).transform).GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
			}
			((Component)__instance).transform.localScale = RadialScale.Value;
			((Component)__instance).transform.Find("ElementInfo").localScale = ElementInfoScale.Value;
			((Component)__instance).transform.Find("InventoryInfo").localScale = InventoryInfoScale.Value;
			((Component)__instance).transform.Find("InventoryInfo/ItemTooltip").localScale = TooltipScale.Value;
			((Component)__instance).transform.Find("InventoryInfo/InventoryWeight").localScale = WeightScale.Value;
			((Component)__instance).transform.Find("InventoryInfo/InventoryArmor").localScale = ArmorScale.Value;
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description)
		{
			return ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, description);
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, string description)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		static ValheimRadialPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			ValheimRadialLogger = Logger.CreateLogSource("ValheimRadial");
			ActivationMode = null;
			OpenKey = null;
			EmoteKey = null;
			CloseKey = null;
			RadialScale = null;
			ElementInfoScale = null;
			InventoryInfoScale = null;
			TooltipScale = null;
			WeightScale = null;
			ArmorScale = null;
			RadialLocation = null;
			AudioFeedback = null;
			InvRowStart = null;
			InvRowCount = null;
			InvIncludeEmptySlots = null;
			InvFilterMode = null;
			InvFilterEquippedOnly = null;
			InvCustomNameFilter = null;
		}
	}
	public static class KeyboardExtensions
	{
		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}
	}
	public static class ToggleExtentions
	{
		public static bool IsOn(this ValheimRadialPlugin.Toggle value)
		{
			return value == ValheimRadialPlugin.Toggle.On;
		}

		public static bool IsOff(this ValheimRadialPlugin.Toggle value)
		{
			return value == ValheimRadialPlugin.Toggle.Off;
		}
	}
}
namespace ValheimRadial.Utilities
{
	internal enum RadialContextKind
	{
		None,
		Inventory,
		Emote
	}
	public enum RadialActivationMode
	{
		Toggle,
		Hold
	}
	public enum InventoryRowFilterMode
	{
		AllItems,
		WeaponsAndTools,
		WeaponsToolsShields,
		ArmorAndUtility,
		ConsumablesOnly,
		CustomNameWhitelist
	}
	internal static class PcRadialState
	{
		private const float MinToggleInterval = 0.15f;

		private const float MinProfileCycleInterval = 0.12f;

		internal static bool IsPcRadialOpen;

		internal static RadialContextKind CurrentContext = RadialContextKind.None;

		private static bool ExplicitCloseRequested;

		private static Func<bool>? OriginalGetClose;

		private static Func<bool>? OriginalGetBack;

		private static float LastToggleTime;

		private static float LastProfileChangeTime;

		internal static InventoryRowFilterMode[] ProfileOrder = Array.Empty<InventoryRowFilterMode>();

		internal static int CurrentProfileIndex;

		internal static bool CanToggleNow()
		{
			return Time.unscaledTime - LastToggleTime >= 0.15f;
		}

		internal static void MarkToggle()
		{
			LastToggleTime = Time.unscaledTime;
		}

		internal static void MarkExplicitClose(RadialBase radial)
		{
			ExplicitCloseRequested = true;
		}

		internal static void HijackCloseDelegates(RadialBase radial)
		{
			if (OriginalGetClose == null)
			{
				OriginalGetClose = radial.GetClose;
			}
			if (OriginalGetBack == null)
			{
				OriginalGetBack = radial.GetBack;
			}
			ExplicitCloseRequested = false;
			radial.GetClose = () => ExplicitCloseRequested;
			radial.GetBack = () => false;
		}

		internal static void RestoreCloseDelegates(RadialBase radial)
		{
			if (OriginalGetClose != null)
			{
				radial.GetClose = OriginalGetClose;
			}
			if (OriginalGetBack != null)
			{
				radial.GetBack = OriginalGetBack;
			}
			OriginalGetClose = null;
			OriginalGetBack = null;
			ExplicitCloseRequested = false;
			IsPcRadialOpen = false;
			CurrentContext = RadialContextKind.None;
			radial.CurrentConfig = null;
			radial.CanOpen = true;
			radial.ShouldAnimateIn = true;
			radial.Active = false;
		}

		internal static void EnsureProfilesInitialized()
		{
			if (ProfileOrder.Length == 0)
			{
				List<InventoryRowFilterMode> list = new List<InventoryRowFilterMode>(4)
				{
					InventoryRowFilterMode.AllItems,
					InventoryRowFilterMode.WeaponsToolsShields,
					InventoryRowFilterMode.ConsumablesOnly,
					InventoryRowFilterMode.ArmorAndUtility
				};
				if (!string.IsNullOrWhiteSpace(ValheimRadialPlugin.InvCustomNameFilter.Value))
				{
					list.Add(InventoryRowFilterMode.CustomNameWhitelist);
				}
				ProfileOrder = list.ToArray();
				InventoryRowFilterMode value = ValheimRadialPlugin.InvFilterMode.Value;
				int num = Array.IndexOf(ProfileOrder, value);
				CurrentProfileIndex = ((num >= 0) ? num : 0);
			}
		}

		internal static InventoryRowFilterMode GetActiveFilterMode()
		{
			EnsureProfilesInitialized();
			if (ProfileOrder.Length == 0)
			{
				return ValheimRadialPlugin.InvFilterMode.Value;
			}
			int num = Mathf.Clamp(CurrentProfileIndex, 0, ProfileOrder.Length - 1);
			return ProfileOrder[num];
		}

		internal static bool CanCycleProfileNow()
		{
			return Time.unscaledTime - LastProfileChangeTime >= 0.12f;
		}

		internal static void StepProfile(int direction, RadialBase radial)
		{
			EnsureProfilesInitialized();
			if (ProfileOrder.Length <= 1)
			{
				return;
			}
			int num = ProfileOrder.Length;
			int num2 = (CurrentProfileIndex + direction) % num;
			if (num2 < 0)
			{
				num2 += num;
			}
			CurrentProfileIndex = num2;
			LastProfileChangeTime = Time.unscaledTime;
			if (!Object.op_Implicit((Object)(object)radial))
			{
				return;
			}
			radial.ResetAllVariables();
			radial.LoadSettings();
			InventoryRowsRadialConfig inventoryRowsRadialConfig = ScriptableObject.CreateInstance<InventoryRowsRadialConfig>();
			inventoryRowsRadialConfig.InitRadialConfig(radial);
			radial.CurrentConfig = (IRadialConfig)(object)inventoryRowsRadialConfig;
			Object.Destroy((Object)(object)inventoryRowsRadialConfig);
			if (RadialData.SO.EnableToggleAnimation)
			{
				RadialArray<RadialMenuElement> elements = radial.m_elements;
				if (elements != null && elements.Count > 0)
				{
					radial.StartAnimatingIn();
				}
			}
			ElementInfo elementInfo = radial.m_elementInfo;
			elementInfo.Alpha = 1f;
			elementInfo.m_inventoryInfo.SetAlpha(1f);
			elementInfo.Radius = RadialData.SO.ElementInfoRadius;
			switch (GetActiveFilterMode())
			{
			case InventoryRowFilterMode.AllItems:
				((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$radial_all"), 0, (Sprite)null);
				break;
			case InventoryRowFilterMode.WeaponsAndTools:
				((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$radial_weapons_tools"), 0, (Sprite)null);
				break;
			case InventoryRowFilterMode.WeaponsToolsShields:
				((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$radial_weapons_tools") + " & " + Localization.instance.Localize("$skill_shields"), 0, (Sprite)null);
				break;
			case InventoryRowFilterMode.ArmorAndUtility:
				((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$radial_armor_utility"), 0, (Sprite)null);
				break;
			case InventoryRowFilterMode.ConsumablesOnly:
				((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$radial_consumables"), 0, (Sprite)null);
				break;
			case InventoryRowFilterMode.CustomNameWhitelist:
				((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$settings_quality_mode_customized"), 0, (Sprite)null);
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
		}
	}
	public static class InventoryRowFilter
	{
		public static HashSet<string> ParseCustomNameList(string raw)
		{
			if (!string.IsNullOrWhiteSpace(raw))
			{
				return new HashSet<string>(from s in raw.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
					select s.Trim() into s
					where !string.IsNullOrEmpty(s)
					select s, StringComparer.OrdinalIgnoreCase);
			}
			return null;
		}

		public static bool PassesFilter(ItemData item, InventoryRowFilterMode mode, HashSet<string> customNames)
		{
			//IL_0074: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Invalid comparison between Unknown and I4
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Invalid comparison between Unknown and I4
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Invalid comparison between Unknown and I4
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Invalid comparison between Unknown and I4
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Invalid comparison between Unknown and I4
			if (item == null)
			{
				return false;
			}
			SharedData shared = item.m_shared;
			switch (mode)
			{
			case InventoryRowFilterMode.AllItems:
				return true;
			case InventoryRowFilterMode.WeaponsAndTools:
				return IsWeaponOrTool(shared, item);
			case InventoryRowFilterMode.WeaponsToolsShields:
				if (!IsWeaponOrTool(shared, item))
				{
					return (int)shared.m_itemType == 5;
				}
				return true;
			case InventoryRowFilterMode.ArmorAndUtility:
			{
				bool flag = IsArmor(shared);
				if (!flag)
				{
					ItemType itemType = shared.m_itemType;
					bool flag2 = (((int)itemType == 18 || (int)itemType == 24) ? true : false);
					flag = flag2;
				}
				return flag;
			}
			case InventoryRowFilterMode.ConsumablesOnly:
			{
				ItemType itemType = shared.m_itemType;
				if ((int)itemType == 2 || (int)itemType == 9 || (int)itemType == 23)
				{
					return true;
				}
				return false;
			}
			case InventoryRowFilterMode.CustomNameWhitelist:
			{
				if (customNames == null || customNames.Count == 0)
				{
					return false;
				}
				string name = shared.m_name;
				string text = (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : null);
				if (!string.IsNullOrEmpty(name) && customNames.Contains(name))
				{
					return true;
				}
				if (!string.IsNullOrEmpty(text))
				{
					return customNames.Contains(text);
				}
				return false;
			}
			default:
				return true;
			}
		}

		private static bool IsWeaponOrTool(SharedData shared, ItemData item)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if (item.IsWeapon())
			{
				return true;
			}
			return (int)shared.m_itemType == 19;
		}

		private static bool IsArmor(SharedData shared)
		{
			//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)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			ItemType itemType = shared.m_itemType;
			if (itemType - 6 <= 1 || (int)itemType == 11 || itemType - 17 <= 1)
			{
				return true;
			}
			return false;
		}
	}
}