using System; using System.Collections.Generic; using System.Diagnostics; 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 System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using OutwardEnchantmentsViewer.Enchantments; using OutwardEnchantmentsViewer.Managers; using OutwardEnchantmentsViewer.UI; using OutwardEnchantmentsViewer.Utility.Enums; using OutwardEnchantmentsViewer.Utility.Fixers; using OutwardEnchantmentsViewer.Utility.Helpers; using SideLoader; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("OutwardEnchantmentsViewer")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OutwardEnchanmentsViewe")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c5450fe0-edcf-483f-b9ea-4b1ef9d36da7")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace OutwardEnchantmentsViewer { [BepInPlugin("gymmed.outwardenchantmentsviewer", "Outward Enchantments Viewer", "0.0.1")] public class OutwardEnchantmentsViewer : BaseUnityPlugin { [HarmonyPatch(typeof(ItemDetailsDisplay), "OnScrollDownPressed")] public class Patch_OnScrollDownPressed { private static bool Prefix(ItemDetailsDisplay __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_movingScrollview) { return false; } float viewPortSize = __instance.m_viewPortSize; Rect rect = __instance.m_contentScrollView.content.rect; float num = viewPortSize / ((Rect)(ref rect)).height; __instance.m_targetScrollPos = Mathf.Clamp(__instance.m_contentScrollView.verticalNormalizedPosition - num, 0f, 1f); __instance.m_movingScrollview = true; ((Selectable)__instance.m_btnScrollDown).interactable = false; ((Selectable)__instance.m_btnScrollUp).interactable = false; return false; } } [HarmonyPatch(typeof(ItemDetailsDisplay), "OnScrollUpPressed")] public class Patch_OnScrollUpPressed { private static bool Prefix(ItemDetailsDisplay __instance) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_movingScrollview) { return false; } float viewPortSize = __instance.m_viewPortSize; Rect rect = __instance.m_contentScrollView.content.rect; float num = viewPortSize / ((Rect)(ref rect)).height; __instance.m_targetScrollPos = Mathf.Clamp(__instance.m_contentScrollView.verticalNormalizedPosition + num, 0f, 1f); __instance.m_movingScrollview = true; ((Selectable)__instance.m_btnScrollDown).interactable = false; ((Selectable)__instance.m_btnScrollUp).interactable = false; return false; } } [HarmonyPatch(typeof(CharacterUI))] [HarmonyPatch(/*Could not decode attribute arguments.*/)] public class CharacterUI_SetTargetCharacterPatch { [HarmonyPostfix] private static void Postfix(CharacterUI __instance) { try { new ItemDescriptionScrollFixer(__instance); ItemDisplayManager.Instance.CreateSection(__instance); } catch (Exception ex) { SL.Log(prefix + " CharacterUI@SetTargetCharacter error: " + ex.Message); } } } [HarmonyPatch(typeof(ItemDetailsDisplay))] [HarmonyPatch(/*Could not decode attribute arguments.*/)] public class ItemDetailsDisplay_RefreshDetailsPatch { [HarmonyPostfix] private static void Postfix(ItemDetailsDisplay __instance) { try { CharacterUI characterUI = ((UIElement)__instance).CharacterUI; if (!Object.op_Implicit((Object)(object)characterUI)) { return; } ItemDisplay itemDisplay = __instance.itemDisplay; Item val = ((itemDisplay != null) ? itemDisplay.RefItem : null); ItemDisplayManager.Instance.ShowOriginalDescription(characterUI); Character localCharacter = ((UIElement)__instance).LocalCharacter; CharacterInventory val2 = ((localCharacter != null) ? localCharacter.Inventory : null); if (!Object.op_Implicit((Object)(object)val2)) { return; } if (!(val is Equipment)) { EnchantmentRecipeItem val3 = (EnchantmentRecipeItem)(object)((val is EnchantmentRecipeItem) ? val : null); if (val3 != null) { ItemDescriptionsManager.Instance.SetEnchantmentsDescription(val3, val2, characterUI); ItemDisplayManager.Instance.HideDisabledDescription(characterUI); } else { ItemDisplayManager.Instance.HideDescription(characterUI); ItemDisplayManager.Instance.HideDisabledDescription(characterUI); } } else if (val.IsNonEnchantable) { ItemDisplayManager.Instance.HideDescription(characterUI); ItemDisplayManager.Instance.HideDisabledDescription(characterUI); } else { ItemDescriptionsManager.Instance.SetEquipmentsEnchantmentsDescription(val, val2, characterUI); } } catch (Exception ex) { SL.Log(prefix + " ItemDetailsDisplay@RefreshDetails error: " + ex.Message); } } } public const string GUID = "gymmed.outwardenchantmentsviewer"; public const string NAME = "Outward Enchantments Viewer"; public const string VERSION = "0.0.1"; public static string prefix = "[gymmed-Enchantments-Viewer]"; public static ConfigEntry ExampleConfig; public static ManualLogSource Log { get; private set; } public static OutwardEnchantmentsViewer Instance { get; private set; } internal void Awake() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Log.LogMessage((object)"Hello world from Outward Enchantments Viewer 0.0.1!"); Log.LogMessage((object)(prefix + " Logger!")); ExampleConfig = ((BaseUnityPlugin)this).Config.Bind("ExampleCategory", "ExampleSetting", false, "This is an example setting."); new Harmony("gymmed.outwardenchantmentsviewer").PatchAll(); } internal void Update() { } } } namespace OutwardEnchantmentsViewer.Utility.Helpers { public class EnchantmentInformationHelper { public static string GetDamageListDescription(Enchantment enchantment) { string text = ""; if (enchantment.DamageBonus.Count < 1) { return text; } int num = enchantment.DamageBonus.Count - 1; DamageType damageType = enchantment.DamageBonus[0]; text += GetDamageDescription(damageType, fullGrowthWords: true); for (int i = 1; i < num; i++) { damageType = enchantment.DamageBonus[i]; text = text + ", " + GetDamageDescription(damageType); } if (num > 0) { damageType = enchantment.DamageBonus[num]; text = text + " and " + GetDamageDescription(damageType); } return text + "\n\n"; } private static string GetDamageDescription(DamageType damageType, bool fullGrowthWords = false) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) string arg = ""; if (fullGrowthWords) { arg = "Lose "; if (damageType.Damage > 0f) { arg = "Gain +"; } } else if (damageType.Damage > 0f) { arg = "+"; } return $"{arg}{damageType.Damage} flat {damageType.Type} damage"; } public static string GetModifiersListDescriptions(Enchantment enchantment) { string text = ""; if (enchantment.DamageModifier.Count < 1) { return text; } int num = enchantment.DamageModifier.Count - 1; DamageType damageType = enchantment.DamageModifier[0]; text += GetModifierDescription(damageType, fullGrowthWords: true); for (int i = 1; i < num; i++) { damageType = enchantment.DamageModifier[i]; text = text + ", " + GetModifierDescription(damageType); } if (num > 0) { damageType = enchantment.DamageModifier[num]; text = text + " and " + GetModifierDescription(damageType); } return text + "\n\n"; } private static string GetModifierDescription(DamageType damageType, bool fullGrowthWords = false) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) string arg = ""; if (fullGrowthWords) { arg = "Lose "; if (damageType.Damage > 0f) { arg = "Gain +"; } } else if (damageType.Damage > 0f) { arg = "+"; } return $"{arg}{damageType.Damage}% {damageType.Type} Damage Bonus"; } public static string GetAdditionalDamagesDescription(Enchantment enchantment) { //IL_0023: 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) //IL_0030: 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) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) string text = ""; if (enchantment.AdditionalDamages.Count() < 1) { return text; } AdditionalDamage[] additionalDamages = enchantment.AdditionalDamages; foreach (AdditionalDamage val in additionalDamages) { string arg = "Removes "; if (val.ConversionRatio > 0f) { arg = "Adds +"; } string arg2 = ((int)Math.Round(val.ConversionRatio * 100f, 0)).ToString(); text = text + $"{arg}{arg2}% of the existing weapon's {val.SourceDamageType}" + $" damage as {val.BonusDamageType} damage \n\n"; } return text; } public static string GetStatModificationsDescription(Enchantment enchantment) { string text = ""; if (enchantment.StatModifications.Count < 1) { return text; } int num = enchantment.StatModifications.Count - 1; StatModification statModification = enchantment.StatModifications[0]; text += GetStatModificationDescription(statModification, fullGrowthWords: true); for (int i = 1; i < num; i++) { statModification = enchantment.StatModifications[i]; text = text + ", " + GetStatModificationDescription(statModification); } if (num > 0) { statModification = enchantment.StatModifications[num]; text = text + " and " + GetStatModificationDescription(statModification); } return text + "\n\n"; } private static string GetStatModificationDescription(StatModification statModification, bool fullGrowthWords = false) { string text = ""; string text2 = Regex.Replace(((object)(Stat)(ref statModification.Name)).ToString(), "(? 0f) { text = "Adds +"; } } else if (statModification.Value > 0f) { text = "+"; } string text3 = ((((object)(BonusType)(ref statModification.Type)).ToString() == "Modifier") ? "% " : (" " + ((object)(BonusType)(ref statModification.Type)).ToString() + " ")); return text + statModification.Value + text3 + text2; } public static string GetElementalResistancesDescription(Enchantment enchantment) { string text = ""; if (enchantment.ElementalResistances.Count < 1) { return text; } int num = enchantment.ElementalResistances.Count - 1; DamageType damageType = enchantment.ElementalResistances[0]; text += GetElementalResistanceDescription(damageType, fullGrowthWords: true); for (int i = 1; i < num; i++) { damageType = enchantment.ElementalResistances[i]; text = text + ", " + GetElementalResistanceDescription(damageType); } if (num > 0) { damageType = enchantment.ElementalResistances[num]; text = text + " and " + GetElementalResistanceDescription(damageType); } return text + "\n\n"; } private static string GetElementalResistanceDescription(DamageType damageType, bool fullGrowthWords = false) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) string arg = ""; if (fullGrowthWords) { arg = "Removes "; if (damageType.Damage > 0f) { arg = "Adds +"; } } else if (damageType.Damage > 0f) { arg = "+"; } return $"{arg}{damageType.Damage}% {damageType.Type} resistance"; } public static string GetEffectsDescription(Enchantment enchantment) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) string text = ""; if (enchantment.Effects.Count() < 1) { return text; } GenericHelper.SplitDerivedClasses(enchantment.Effects, out var remainingArray, out var derivedArray); text += GetAddStatusEffectBuildUpDescription(derivedArray); GenericHelper.SplitDerivedClasses(remainingArray, out remainingArray, out var derivedArray2); ShootEnchantmentBlast[] array = derivedArray2; foreach (ShootEnchantmentBlast val in array) { string text2 = text; Blast baseBlast = ((ShootBlast)val).BaseBlast; text = text2 + $"Weapon deals an AoE {((baseBlast != null) ? ((Component)baseBlast).GetComponentInChildren()?.OverrideDType : null)} \"Blast\" with " + $"{val.DamageMultiplier}x damage multiplier (based on Weapon's total base damage) \n\n"; } GenericHelper.SplitDerivedClasses(remainingArray, out remainingArray, out var derivedArray3); text += GetAffectStatusEffectBuildUpResistancesDescription(derivedArray3); GenericHelper.SplitDerivedClasses(remainingArray, out remainingArray, out var derivedArray4); text += GetAddStatusEffectsDescription(derivedArray4); Effect[] array2 = remainingArray; foreach (Effect val2 in array2) { text += $"Type: {((object)val2).GetType()}"; } return text + "\n"; } private static string GetAddStatusEffectBuildUpDescription(AddStatusEffectBuildUp[] derivedStatusEffects) { string text = ""; if (derivedStatusEffects.Length < 1) { return text; } int num = derivedStatusEffects.Length - 1; AddStatusEffectBuildUp val = derivedStatusEffects[0]; text = text + "Weapon now inflicts " + val.Status.StatusName + " " + $"({val.BuildUpValue}% buildup)"; for (int i = 1; i < num; i++) { val = derivedStatusEffects[i]; text = text + ", " + val.Status.StatusName + " " + $"({val.BuildUpValue}% buildup)"; } if (num > 0) { val = derivedStatusEffects[num]; text = text + " and " + val.Status.StatusName + " " + $"({val.BuildUpValue}% buildup) \n\n"; } return text; } private static string GetAffectStatusEffectBuildUpResistancesDescription(AffectStatusEffectBuildUpResistance[] derivedStatusResistances) { string text = ""; if (derivedStatusResistances.Length < 1) { return text; } int num = derivedStatusResistances.Length - 1; AffectStatusEffectBuildUpResistance val = derivedStatusResistances[0]; text = text + "Euipment now provides " + val.StatusEffect.StatusName + " " + $"({val.RealValue}% buildup) resistance"; for (int i = 0; i < num; i++) { val = derivedStatusResistances[i]; text = text + ", " + val.StatusEffect.StatusName + " " + $"({val.RealValue}% buildup) resistance"; } if (num > 0) { val = derivedStatusResistances[num]; text = text + " and " + val.StatusEffect.StatusName + " " + $"({val.RealValue}% buildup) resistance \n"; } return text; } private static string GetAddStatusEffectsDescription(AddStatusEffect[] derivedAddStatusEffect) { string text = ""; if (derivedAddStatusEffect.Length < 1) { return text; } int num = derivedAddStatusEffect.Length - 1; AddStatusEffect val = null; string text2 = ""; for (int i = 0; i < derivedAddStatusEffect.Length; i++) { val = derivedAddStatusEffect[i]; text2 = ((val.ChancesToContract <= 0) ? "" : "+"); text = ((i != 0) ? ((i != num) ? (text + ", " + val.Status.StatusName + " " + $"({text2}{val.ChancesToContract})") : (text + " and " + val.Status.StatusName + " " + $"({text2}{val.ChancesToContract}) \n")) : (text + "Euipment now contracts " + val.Status.StatusName + " " + $"({text2}{val.ChancesToContract})")); } return text; } } public class EnchantmentsHelper { public static string GetEnchantmentArmorIngrediantType(EnchantmentRecipe recipe) { //IL_0012: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) IngredientData[] compatibleEquipments = recipe.CompatibleEquipments.CompatibleEquipments; foreach (IngredientData val in compatibleEquipments) { Item specificIngredient = val.SpecificIngredient; Armor val2 = (Armor)(object)((specificIngredient is Armor) ? specificIngredient : null); if (val2 != null) { return ((object)(EquipmentSlotIDs)(ref ((Equipment)val2).EquipSlot)).ToString(); } Item specificIngredient2 = val.SpecificIngredient; Weapon val3 = (Weapon)(object)((specificIngredient2 is Weapon) ? specificIngredient2 : null); if (val3 != null) { return ((Item)val3).TypeDisplay.ToString(); } } return ""; } public static string GetEnchantmentDescription(EnchantmentRecipeItem enchantmentItem) { return ((Item)enchantmentItem).Name + " \n"; } public static string GetEnchantmentsDescriptions(List enchantmentRecipesDatas) { string text = ""; foreach (EnchantmentRecipeData enchantmentRecipesData in enchantmentRecipesDatas) { text += GetEnchantmentDescription(enchantmentRecipesData.item); } return text; } public static string GetEnchantmentsDescriptions(List enchantmentRecipes) { string text = ""; foreach (EnchantmentRecipe enchantmentRecipe in enchantmentRecipes) { Enchantment enchantmentPrefab = ResourcesPrefabManager.Instance.GetEnchantmentPrefab(enchantmentRecipe.RecipeID); text = text + "Enchanting: " + enchantmentPrefab.Name + " \n"; } return text; } public static List GetAvailableEnchantmentRecipeDatasInInventory(Item item, CharacterInventory inventory) { List allItemsOfType = ItemHelpers.GetAllItemsOfType(ItemHelpers.GetUniqueItemsInInventory(inventory)); List list = new List(); foreach (EnchantmentRecipeItem item2 in allItemsOfType) { EnchantmentRecipe[] recipes = item2.Recipes; foreach (EnchantmentRecipe val in recipes) { if (val.GetHasMatchingEquipment(item)) { list.Add(new EnchantmentRecipeData(item2, val)); } } } return list; } public static List GetAvailableEnchantmentRecipeItemsInInventory(Item item, CharacterInventory inventory) { List allItemsOfType = ItemHelpers.GetAllItemsOfType(ItemHelpers.GetUniqueItemsInInventory(inventory)); List list = new List(); foreach (EnchantmentRecipeItem item2 in allItemsOfType) { EnchantmentRecipe[] recipes = item2.Recipes; for (int i = 0; i < recipes.Length; i++) { if (recipes[i].GetHasMatchingEquipment(item)) { list.Add(item2); } } } return list; } public static List GetAvailableEnchantmentRecipies(Item item) { List enchantmentRecipes = RecipeManager.Instance.GetEnchantmentRecipes(); List list = new List(); foreach (EnchantmentRecipe item2 in enchantmentRecipes) { if (item2.GetHasMatchingEquipment(item)) { list.Add(item2); } } return list; } public static List GetMissingEnchantments(List availableEnchantments, List haveEnchantments) { List list = new List(); bool flag = false; foreach (EnchantmentRecipe availableEnchantment in availableEnchantments) { foreach (EnchantmentRecipe haveEnchantment in haveEnchantments) { if (availableEnchantment.RecipeID == haveEnchantment.RecipeID) { flag = true; } } if (flag) { flag = false; } else { list.Add(availableEnchantment); } } return list; } } public class GenericHelper { public static void SplitDerivedClasses(TBase[] sourceArray, out TBase[] remainingArray, out TDerived[] derivedArray) { List list = new List(); List list2 = new List(); foreach (TBase val in sourceArray) { if (val is TDerived) { object obj = val; TDerived item = (TDerived)((obj is TDerived) ? obj : null); list.Add(item); } else { list2.Add(val); } } derivedArray = list.ToArray(); remainingArray = list2.ToArray(); } public static int CountDerivedClassesInArray(T[] array, Type TypeToCount) { int num = 0; for (int i = 0; i < array.Length; i++) { T val = array[i]; if (val != null && TypeToCount.IsAssignableFrom(val.GetType())) { num++; } } return num; } public static int CountDerivedClassesInList(List list, Type TypeToCount) { int num = 0; foreach (T item in list) { if (item != null && TypeToCount.IsAssignableFrom(item.GetType())) { num++; } } return num; } } public class ItemHelpers { public static List GetAllItemsOfType(List items) where T : Item { List list = new List(); foreach (Item item in items) { T val = (T)(object)((item is T) ? item : null); if (val != null) { list.Add(val); } } return list; } public static List GetUniqueItemsInInventory(CharacterInventory inventory) { ItemContainer pouch = inventory.Pouch; List first = ((pouch != null) ? pouch.GetContainedItems() : null); List second = new List(); if (inventory.HasABag) { second = ((ItemContainer)inventory.EquippedBag.Container).GetContainedItems(); } return first.Union(second).ToList(); } } } namespace OutwardEnchantmentsViewer.Utility.Fixers { public class ItemDescriptionScrollFixer { private CharacterUI _characterUI; private Button _btnScrollUpButton; private Button _btnScrollDownButton; private ScrollRect _scrollView; private RectTransform _viewport; public Button BtnScrollUpButton { get { return _btnScrollUpButton; } set { _btnScrollUpButton = value; } } public Button BtnScrollDownButton { get { return _btnScrollDownButton; } set { _btnScrollDownButton = value; } } public ScrollRect ScrollView { get { return _scrollView; } set { _scrollView = value; } } public RectTransform Viewport { get { return _viewport; } set { _viewport = value; } } public CharacterUI CharacterUI { get { return _characterUI; } set { _characterUI = value; } } public ItemDescriptionScrollFixer(CharacterUI characterUI) { CharacterUI = characterUI; CreateFixer(characterUI); } public void CreateFixer(CharacterUI characterUI) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown Transform val = ((Component)characterUI).transform.Find("Canvas/GameplayPanels/Menus/CharacterMenus/MainPanel/Content/MiddlePanel/Inventory/DetailPanel/ItemDetailsPanel/ItemDetails/"); if (Object.op_Implicit((Object)(object)val)) { Transform obj = val.Find("btnScrollUp"); BtnScrollUpButton = ((obj != null) ? ((Component)obj).GetComponent