Decompiled source of ShieldRestyler v1.0.1

ShieldRestyler.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using ShieldRestyler.Data;
using ShieldRestyler.Patches;
using UnityEngine;
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: AssemblyTitle("ShieldRestyler")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("HP")]
[assembly: AssemblyProduct("ShieldRestyler")]
[assembly: AssemblyCopyright("Copyright © HP 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4b016a14-be14-4ddd-b106-a3020d02e2e3")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ShieldRestyler
{
	[BepInPlugin("YouDied.ShieldRestyler", "Shield Restyler", "1.0.1")]
	[BepInProcess("valheim.exe")]
	public class ShieldRestylerPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "YouDied.ShieldRestyler";

		public const string PluginName = "Shield Restyler";

		public const string PluginVersion = "1.0.1";

		internal static ManualLogSource Log;

		public static ConfigEntry<KeyboardShortcut> OpenStylerKey;

		private readonly Harmony _harmony = new Harmony("YouDied.ShieldRestyler");

		private void Awake()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			OpenStylerKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "OpenStylerKey", new KeyboardShortcut((KeyCode)96, Array.Empty<KeyCode>()), "Press while hovering a shield in the inventory grid to cycle its visual style.");
			_harmony.PatchAll();
			InventoryGui_Patches.Apply(_harmony);
			ManualLogSource log = Log;
			KeyboardShortcut value = OpenStylerKey.Value;
			log.LogInfo((object)string.Format("{0} {1} loaded. Press [{2}] while hovering a shield to cycle styles.", "Shield Restyler", "1.0.1", ((KeyboardShortcut)(ref value)).MainKey));
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
		}
	}
}
namespace ShieldRestyler.Patches
{
	public static class InventoryGui_Patches
	{
		internal static ItemData LastHoveredShield;

		public static void Apply(Harmony harmony)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			MethodInfo method = typeof(InventoryGui).GetMethod("Update", bindingAttr);
			if (method != null)
			{
				harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(InventoryGui_Patches), "Update_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				ShieldRestylerPlugin.Log.LogInfo((object)"[ShieldRestyler] Patched InventoryGui.Update");
			}
		}

		private static void Update_Postfix()
		{
			//IL_0019: 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)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!InventoryGui.IsVisible())
			{
				return;
			}
			KeyboardShortcut value = ShieldRestylerPlugin.OpenStylerKey.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			if (Input.GetKeyDown(mainKey) && LastHoveredShield != null)
			{
				string prefabName = GetPrefabName(LastHoveredShield);
				if (ShieldVariantDatabase.HasVariants(prefabName))
				{
					List<string> variants = ShieldVariantDatabase.GetVariants(prefabName);
					int num = (LastHoveredShield.m_variant + 1) % variants.Count;
					LastHoveredShield.m_variant = num;
					string slotKey = StyleSaveData.MakeSlotKey(LastHoveredShield);
					StyleSaveData.SetChoice(slotKey, num);
					ShieldRestylerPlugin.Log.LogInfo((object)$"[ShieldRestyler] {LastHoveredShield.m_shared.m_name} → variant {num} ({variants[num]})");
				}
			}
		}

		internal static string GetPrefabName(ItemData item)
		{
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name;
			}
			string text = item.m_shared.m_name.Replace("$item_", "");
			string[] array = text.Split(new char[1] { '_' });
			StringBuilder stringBuilder = new StringBuilder();
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				if (text2.Length > 0)
				{
					stringBuilder.Append(char.ToUpper(text2[0])).Append(text2.Substring(1));
				}
			}
			return stringBuilder.ToString();
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	public static class InventoryGrid_UpdateGui_Patch
	{
		private static FieldInfo _elementsField;

		private static PropertyInfo _positionProp;

		private static MethodInfo _getRectMethod;

		private static bool _ready;

		[HarmonyPostfix]
		private static void Postfix(InventoryGrid __instance)
		{
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Invalid comparison between Unknown and I4
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.m_localPlayer == (Object)null || __instance.GetInventory() != ((Humanoid)Player.m_localPlayer).GetInventory() || !InventoryGui.IsVisible())
			{
				return;
			}
			if (!_ready)
			{
				BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				_elementsField = typeof(InventoryGrid).GetField("m_elements", bindingFlags);
				if (_elementsField == null)
				{
					Log("m_elements field not found");
					return;
				}
				if (!(_elementsField.GetValue(__instance) is IList { Count: not 0 } list))
				{
					return;
				}
				Type type = list[0].GetType();
				_positionProp = type.GetProperty("Position", bindingFlags | BindingFlags.GetProperty);
				if (_positionProp == null)
				{
					FieldInfo field = type.GetField("<Position>k__BackingField", bindingFlags);
					if (!(field != null))
					{
						Log("Position property/field not found on element type");
						return;
					}
					_elementsField = _elementsField;
					Log("Using backing field for Position on " + type.Name);
				}
				_getRectMethod = type.GetMethod("GetElementRectTransform", bindingFlags);
				if (_getRectMethod == null)
				{
					Log("GetElementRectTransform not found — falling back to m_button");
				}
				_ready = true;
				Log("InventoryGrid fields resolved on type '" + type.Name + "'.");
			}
			if (!_ready || !(_elementsField.GetValue(__instance) is IList list2))
			{
				return;
			}
			Inventory inventory = __instance.GetInventory();
			Vector3 mousePosition = Input.mousePosition;
			ItemData val = null;
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			foreach (object item in list2)
			{
				RectTransform val2 = null;
				if (_getRectMethod != null)
				{
					object? obj = _getRectMethod.Invoke(item, null);
					val2 = (RectTransform)((obj is RectTransform) ? obj : null);
				}
				if ((Object)(object)val2 == (Object)null)
				{
					object? obj2 = item.GetType().GetField("m_button", bindingAttr)?.GetValue(item);
					Button val3 = (Button)((obj2 is Button) ? obj2 : null);
					val2 = ((val3 != null) ? ((Component)val3).GetComponent<RectTransform>() : null);
				}
				if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy || !RectTransformUtility.RectangleContainsScreenPoint(val2, Vector2.op_Implicit(mousePosition)))
				{
					continue;
				}
				Vector2i val4;
				if (_positionProp != null)
				{
					val4 = (Vector2i)_positionProp.GetValue(item);
				}
				else
				{
					FieldInfo field2 = item.GetType().GetField("<Position>k__BackingField", bindingAttr);
					val4 = (Vector2i)field2.GetValue(item);
				}
				val = inventory.GetItemAt(val4.x, val4.y);
				break;
			}
			InventoryGui_Patches.LastHoveredShield = ((val != null && (int)val.m_shared.m_itemType == 5) ? val : null);
		}

		private static void Log(string msg)
		{
			ShieldRestylerPlugin.Log.LogInfo((object)("[ShieldRestyler] " + msg));
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	public static class Player_OnSpawned_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Game instance = Game.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				PlayerProfile playerProfile = instance.GetPlayerProfile();
				obj = ((playerProfile != null) ? playerProfile.GetName() : null);
			}
			if (obj == null)
			{
				obj = "unknown";
			}
			string characterName = (string)obj;
			StyleSaveData.LoadForCharacter(characterName);
			Inventory inventory = ((Humanoid)__instance).GetInventory();
			if (inventory == null)
			{
				return;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((int)allItem.m_shared.m_itemType == 5)
				{
					string prefabName = (((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : "");
					if (ShieldVariantDatabase.HasVariants(prefabName))
					{
						allItem.m_variant = StyleSaveData.GetChoice(StyleSaveData.MakeSlotKey(allItem));
					}
				}
			}
		}
	}
}
namespace ShieldRestyler.Data
{
	public static class ShieldVariantDatabase
	{
		public static readonly Dictionary<string, List<string>> Variants = new Dictionary<string, List<string>>
		{
			{
				"ShieldWood",
				new List<string> { "Plain", "Iron Rivets", "Sun Cross", "Spirals" }
			},
			{
				"ShieldWoodTower",
				new List<string> { "Plain", "Diamond", "Cross", "Banded" }
			},
			{
				"ShieldBoneTower",
				new List<string> { "Ribbed", "Skull Face", "Spine Cross", "Jagged" }
			},
			{
				"ShieldBronze",
				new List<string> { "Plain", "Concentric Rings", "Sun Boss", "Etched Rim" }
			},
			{
				"ShieldBronzeBuckler",
				new List<string> { "Plain", "Punched", "Riveted", "Embossed" }
			},
			{
				"ShieldIron",
				new List<string> { "Plain", "Banded", "Studded", "Engraved", "Worn" }
			},
			{
				"ShieldIronTower",
				new List<string> { "Plain", "Flanged", "Cross Guard", "Spiked", "Runic" }
			},
			{
				"ShieldIronBuckler",
				new List<string> { "Smooth", "Hammered", "Punched", "Etched" }
			},
			{
				"ShieldSilver",
				new List<string> { "Plain", "Moon Crest", "Wolf Howl", "Frost Rune", "Dragon Fang", "Blizzard" }
			},
			{
				"ShieldBlackmetal",
				new List<string> { "Plain", "Serpent Eye", "Fuling Glyph", "Death Mark", "Tar Splash", "Runed", "Warlord" }
			},
			{
				"ShieldBlackmetalTower",
				new List<string> { "Plain", "Spiked", "Rune Wall", "Glyph Crest", "War Chief", "Obsidian" }
			},
			{
				"ShieldCarapace",
				new List<string> { "Natural", "Polished", "Cracked", "Runed", "Seeker Glyph" }
			},
			{
				"ShieldCarapaceBuckler",
				new List<string> { "Natural", "Polished", "Cracked", "Runed" }
			},
			{
				"ShieldFlametal",
				new List<string> { "Ember", "Scorched", "Molten", "Ash Rune", "Cinder Crest", "Inferno" }
			},
			{
				"ShieldFlametalTower",
				new List<string> { "Ember", "Scorched", "Molten", "Ash Rune", "Cinder Crest", "Inferno", "Volcanic" }
			},
			{
				"ShieldGold",
				new List<string> { "Style 1", "Style 2", "Style 3", "Style 4", "Style 5" }
			},
			{
				"ShieldGoldTower",
				new List<string> { "Style 1", "Style 2", "Style 3", "Style 4", "Style 5" }
			},
			{
				"ShieldRoots",
				new List<string> { "Style 1", "Style 2", "Style 3" }
			}
		};

		public static bool HasVariants(string prefabName)
		{
			return Variants.ContainsKey(prefabName);
		}

		public static List<string> GetVariants(string prefabName)
		{
			List<string> value;
			return Variants.TryGetValue(prefabName, out value) ? value : null;
		}
	}
	public static class StyleSaveData
	{
		private static readonly string SaveDir = Path.Combine(Paths.ConfigPath, "ShieldRestyler");

		private static Dictionary<string, int> _choices = new Dictionary<string, int>();

		private static string _currentCharacter = "";

		private static ManualLogSource Log => ShieldRestylerPlugin.Log;

		public static int GetChoice(string slotKey)
		{
			int value;
			return _choices.TryGetValue(slotKey, out value) ? value : 0;
		}

		public static void SetChoice(string slotKey, int variant)
		{
			_choices[slotKey] = variant;
			SaveToDisk();
		}

		public static void LoadForCharacter(string characterName)
		{
			_currentCharacter = characterName;
			_choices.Clear();
			string savePath = GetSavePath(characterName);
			if (!File.Exists(savePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(savePath);
			foreach (string text in array)
			{
				if (!string.IsNullOrWhiteSpace(text))
				{
					string[] array2 = text.Split(new char[1] { '=' });
					if (array2.Length == 2 && int.TryParse(array2[1], out var result))
					{
						_choices[array2[0]] = result;
					}
				}
			}
			Log.LogDebug((object)$"[StyleSaveData] Loaded {_choices.Count} choices for '{characterName}'.");
		}

		private static void SaveToDisk()
		{
			if (string.IsNullOrEmpty(_currentCharacter))
			{
				return;
			}
			Directory.CreateDirectory(SaveDir);
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, int> choice in _choices)
			{
				list.Add($"{choice.Key}={choice.Value}");
			}
			File.WriteAllLines(GetSavePath(_currentCharacter), list);
		}

		private static string GetSavePath(string characterName)
		{
			return Path.Combine(SaveDir, characterName + ".cfg");
		}

		public static string MakeSlotKey(ItemData item)
		{
			string arg = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : item.m_shared.m_name);
			return $"{arg}_{item.m_gridPos.x}_{item.m_gridPos.y}";
		}
	}
}