Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Simple Item Upgrade Preview v1.0.0
BepInEx/plugins/SimpleItemUpgradePreview/SimpleItemUpgradePreview.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using BepInEx; using HarmonyLib; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace SimpleUpgradePreview; [BepInPlugin("local.che.simpleupgradepreview", "Simple Item Upgrade Preview", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "local.che.simpleupgradepreview"; private Harmony harmony; internal static Plugin Instance; internal static bool Failed; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Instance = this; try { PreviewPatch.ValidateApi(); harmony = new Harmony("local.che.simpleupgradepreview"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Simple Item Upgrade Preview ready: current -> next stats in the Upgrade panel."); } catch (Exception error) { StopPreview(error); } } internal static void StopPreview(Exception error) { if (!Failed) { Failed = true; ((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Upgrade preview disabled; normal crafting remains available. " + error)); } } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } Instance = null; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] internal static class PreviewPatch { internal struct Context { public ItemData Item; public int Quality; } private static readonly FieldInfo Selected = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); private static MethodInfo getItem; private static MethodInfo getRecipe; private static ItemData cachedItem; private static int cachedQuality; private static string cachedInput; private static string cachedOutput; private static float refreshAt; private static readonly string[] Tokens = new string[16] { "$item_durability", "$item_armor", "$item_blockarmor", "$item_blockforce", "$item_parrybonus", "$item_parryadrenaline", "$item_knockback", "$inventory_damage", "$inventory_blunt", "$inventory_slash", "$inventory_pierce", "$inventory_fire", "$inventory_frost", "$inventory_lightning", "$inventory_poison", "$inventory_spirit" }; internal static void ValidateApi() { if (Selected == null) { throw new MissingFieldException("InventoryGui.m_selectedRecipe"); } getItem = AccessTools.PropertyGetter(Selected.FieldType, "ItemData"); getRecipe = AccessTools.PropertyGetter(Selected.FieldType, "Recipe"); if (getItem == null || getRecipe == null) { throw new MissingMemberException("RecipeDataPair accessors"); } } private static void Prefix(InventoryGui __instance, out Context __state) { __state = default(Context); if (Plugin.Failed) { return; } try { object value = Selected.GetValue(__instance); object? obj = getItem.Invoke(value, null); ItemData val = (ItemData)((obj is ItemData) ? obj : null); object? obj2 = getRecipe.Invoke(value, null); Recipe val2 = (Recipe)((obj2 is Recipe) ? obj2 : null); if (val == null || (Object)(object)val2 == (Object)null || val.m_shared == null) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); if (val.m_quality < val.m_shared.m_maxQuality || (!((Object)(object)currentCraftingStation == (Object)null) && currentCraftingStation.m_upgrader)) { __state.Item = val; __state.Quality = val.m_quality; } } } catch (Exception error) { Plugin.StopPreview(error); } } [HarmonyPriority(0)] [HarmonyAfter(new string[] { "randyknapp.mods.epicloot" })] private static void Postfix(InventoryGui __instance, Context __state) { if (Plugin.Failed || __state.Item == null) { return; } try { if (__state.Item.m_quality != __state.Quality) { return; } object value = Selected.GetValue(__instance); if (!object.ReferenceEquals(getItem.Invoke(value, null), __state.Item)) { return; } TMP_Text recipeDecription = __instance.m_recipeDecription; if ((Object)(object)recipeDecription == (Object)null || !((Behaviour)recipeDecription).enabled) { return; } string text = recipeDecription.text; if (object.ReferenceEquals(cachedItem, __state.Item) && cachedQuality == __state.Quality && Time.unscaledTime < refreshAt && (text == cachedInput || text == cachedOutput)) { recipeDecription.text = cachedOutput; return; } HashSet<string> hashSet = new HashSet<string>(); string[] tokens = Tokens; foreach (string text2 in tokens) { hashSet.Add(Localization.instance.Localize(text2)); } string current = Localization.instance.Localize(ItemData.GetTooltip(__state.Item, __state.Quality, true, (float)Game.m_worldLevel, -1, false)); string upgraded = Localization.instance.Localize(ItemData.GetTooltip(__state.Item, __state.Quality + 1, true, (float)Game.m_worldLevel, -1, false)); string text3 = ComparisonText.Apply(text, current, upgraded, hashSet); cachedItem = __state.Item; cachedQuality = __state.Quality; cachedInput = text; cachedOutput = text3; refreshAt = Time.unscaledTime + 0.5f; recipeDecription.text = text3; } catch (Exception error) { Plugin.StopPreview(error); } } } public static class ComparisonText { private static readonly Regex Tags = new Regex("<[^>]+>"); private static readonly Regex Number = new Regex("^[+-]?\\d+(?:[.,]\\d+)?%?"); private static Dictionary<string, string> ReadLines(string text, ISet<string> labels) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); string[] array = text.Split('\n'); foreach (string input in array) { string text2 = Tags.Replace(input, "").Trim(); int num = text2.IndexOf(':'); if (num < 0) { continue; } string text3 = text2.Substring(0, num).Trim(); if (labels.Contains(text3)) { string value = text2.Substring(num + 1).Trim(); if (dictionary.ContainsKey(text3)) { dictionary[text3] = null; } else { dictionary.Add(text3, value); } } } return dictionary; } public static string Apply(string displayed, string current, string upgraded, ISet<string> labels) { if (string.IsNullOrEmpty(displayed) || string.IsNullOrEmpty(current) || string.IsNullOrEmpty(upgraded)) { return displayed; } Dictionary<string, string> dictionary = ReadLines(current, labels); Dictionary<string, string> dictionary2 = ReadLines(upgraded, labels); Dictionary<string, string> dictionary3 = ReadLines(displayed, labels); string[] array = displayed.Split('\n'); for (int i = 0; i < array.Length; i++) { string text = Tags.Replace(array[i], "").Trim(); int num = text.IndexOf(':'); if (num < 0) { continue; } string text2 = text.Substring(0, num).Trim(); if (dictionary.TryGetValue(text2, out var value) && value != null && dictionary2.TryGetValue(text2, out var value2) && value2 != null && dictionary3.TryGetValue(text2, out var value3) && value3 != null) { Match match = Number.Match(value); Match match2 = Number.Match(value2); if (match.Success && match2.Success && !(value == value2)) { string text3 = value2.Substring(match2.Length); array[i] = text2 + ": <color=#BBBBBB>" + match.Value + "</color> → <color=#FFD966>" + match2.Value + "</color>" + text3; } } } return string.Join("\n", array); } }