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 DeepNorthUtilityItems v1.0.0
DeepNorthUtilityItems.dll
Decompiled 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [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 DeepNorthUtilityItems { [HarmonyPatch(typeof(Trader), "Start")] internal static class HaldorStockPatch { private static void Postfix(Trader __instance) { if (!((Object)(object)__instance == (Object)null) && string.Equals(__instance.m_name, "Haldor", StringComparison.Ordinal)) { AddItem(__instance, "IceShoes", ModConfig.IceSpikesHaldorEnabled.Value, ModConfig.IceSpikesHaldorPrice.Value, ModConfig.IceSpikesHaldorStack.Value, ModConfig.IceSpikesHaldorGlobalKey.Value); AddItem(__instance, "IceSkates", ModConfig.IceSkatesHaldorEnabled.Value, ModConfig.IceSkatesHaldorPrice.Value, ModConfig.IceSkatesHaldorStack.Value, ModConfig.IceSkatesHaldorGlobalKey.Value); } } private static void AddItem(Trader trader, string prefabName, bool enabled, int price, int stack, string requiredGlobalKey) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown if (!enabled || (Object)(object)ObjectDB.instance == (Object)null) { return; } foreach (TradeItem item in trader.m_items) { if ((Object)(object)item?.m_prefab != (Object)null && string.Equals(((Object)item.m_prefab).name, prefabName, StringComparison.Ordinal)) { return; } } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName); ItemDrop val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>()); if (!((Object)(object)val == (Object)null)) { trader.m_items.Add(new TradeItem { m_prefab = val, m_price = Math.Max(1, price), m_stack = Math.Max(1, stack), m_requiredGlobalKey = (string.IsNullOrWhiteSpace(requiredGlobalKey) ? string.Empty : requiredGlobalKey.Trim()) }); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ItemIconOverrides { private sealed class IconDefinition { internal readonly string PrefabName; internal readonly string AssetName; internal IconDefinition(string prefabName, string assetName) { PrefabName = prefabName; AssetName = assetName; } } private static readonly IconDefinition[] Definitions = new IconDefinition[2] { new IconDefinition("IceShoes", "Ice Spikes.png"), new IconDefinition("IceSkates", "Ice Skates.png") }; private static readonly Dictionary<string, Sprite> LoadedIcons = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase); private static readonly List<Texture2D> CreatedTextures = new List<Texture2D>(); private static readonly List<Sprite> CreatedSprites = new List<Sprite>(); [HarmonyPostfix] private static void Postfix(ObjectDB __instance) { Apply(__instance); } private static void Apply(ObjectDB objectDb) { if ((Object)(object)objectDb == (Object)null || objectDb.m_items == null) { return; } foreach (GameObject prefab in objectDb.m_items) { if ((Object)(object)prefab == (Object)null) { continue; } IconDefinition iconDefinition = Array.Find(Definitions, (IconDefinition entry) => string.Equals(entry.PrefabName, ((Object)prefab).name, StringComparison.OrdinalIgnoreCase)); if (iconDefinition == null) { continue; } SharedData val = prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared; if (val == null || val.m_icons == null || val.m_icons.Length == 0) { Plugin.Log.LogWarning((object)("Could not apply custom icon because " + iconDefinition.PrefabName + " has no item icon slot.")); continue; } Sprite val2 = LoadIcon(iconDefinition, val.m_icons[0]); if (!((Object)(object)val2 == (Object)null)) { Sprite[] array = (Sprite[])(object)new Sprite[val.m_icons.Length]; for (int num = 0; num < array.Length; num++) { array[num] = val2; } val.m_icons = array; Plugin.Log.LogInfo((object)("Applied custom icon to " + iconDefinition.PrefabName + ".")); } } } private static Sprite LoadIcon(IconDefinition definition, Sprite source) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) if (LoadedIcons.TryGetValue(definition.PrefabName, out var value)) { return value; } string name = "DeepNorthUtilityItems.Assets." + definition.AssetName; try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name); if (stream == null) { Plugin.Log.LogWarning((object)("Embedded icon asset is missing: " + definition.AssetName + ".")); return null; } byte[] array = new byte[(int)stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false, false); if (!LoadPng(val, array)) { Object.Destroy((Object)(object)val); Plugin.Log.LogWarning((object)("Could not decode icon asset: " + definition.AssetName + ".")); return null; } ((Object)val).name = "DeepNorthUtilityItems_" + Path.GetFileNameWithoutExtension(definition.AssetName) + "Texture"; ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; float num = (((Object)(object)source != (Object)null) ? source.pixelsPerUnit : 100f); Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), num, 0u, (SpriteMeshType)0); ((Object)val2).name = "DeepNorthUtilityItems_" + Path.GetFileNameWithoutExtension(definition.AssetName); LoadedIcons[definition.PrefabName] = val2; CreatedTextures.Add(val); CreatedSprites.Add(val2); return val2; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not load icon for " + definition.PrefabName + ": " + ex.Message)); return null; } } private static bool LoadPng(Texture2D texture, byte[] imageData) { Assembly assembly = Array.Find(AppDomain.CurrentDomain.GetAssemblies(), (Assembly loaded) => loaded.GetName().Name == "UnityEngine.ImageConversionModule"); if (assembly == null) { try { assembly = Assembly.Load("UnityEngine.ImageConversionModule"); } catch { return false; } } MethodInfo methodInfo = assembly.GetType("UnityEngine.ImageConversion")?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null); if (methodInfo != null) { return (bool)methodInfo.Invoke(null, new object[3] { texture, imageData, true }); } return false; } } internal static class ItemIntegration { private static bool _recipesRegistered; internal static void Register(ManualLogSource log) { ApplyItemType("IceShoes", log); ApplyItemType("IceSkates", log); if (!_recipesRegistered) { if (ModConfig.IceSpikesCraftEnabled.Value) { RegisterConfiguredRecipe("IceShoes", "Recipe_DeepNorthUtility_IceSpikes", ModConfig.IceSpikesStation.Value, ModConfig.IceSpikesStationLevel.Value, ModConfig.IceSpikesIngredients.Value, log); } if (ModConfig.IceSkatesCraftEnabled.Value) { RegisterConfiguredRecipe("IceSkates", "Recipe_DeepNorthUtility_IceSkates", ModConfig.IceSkatesStation.Value, ModConfig.IceSkatesStationLevel.Value, ModConfig.IceSkatesIngredients.Value, log); } _recipesRegistered = true; } } private static void RegisterConfiguredRecipe(string item, string recipeName, string station, int stationLevel, string ingredients, ManualLogSource log) { if (!TryParseRequirements(ingredients, out var requirements, out var error)) { log.LogWarning((object)("Skipped " + recipeName + " for " + item + ": invalid Ingredients value. " + error)); } else { AddRecipe(item, recipeName, station, stationLevel, requirements, log); } } private static bool TryParseRequirements(string ingredients, out RequirementConfig[] requirements, out string error) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown requirements = Array.Empty<RequirementConfig>(); error = null; if (string.IsNullOrWhiteSpace(ingredients)) { error = "Enter at least one pair in the form PrefabID:amount."; return false; } List<RequirementConfig> list = new List<RequirementConfig>(); string[] array = ingredients.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); int num = text.LastIndexOf(':'); if (num <= 0 || num == text.Length - 1) { error = "'" + text + "' is not in the form PrefabID:amount."; return false; } string text2 = text.Substring(0, num).Trim(); if (!int.TryParse(text.Substring(num + 1).Trim(), out var result) || result <= 0) { error = "'" + text + "' must use a positive whole-number amount."; return false; } if (string.IsNullOrWhiteSpace(text2)) { error = "Ingredient prefab IDs cannot be empty."; return false; } list.Add(new RequirementConfig(text2, result, 0, true)); } requirements = list.ToArray(); return requirements.Length != 0; } private static void AddRecipe(string item, string recipeName, string station, int stationLevel, RequirementConfig[] requirements, ManualLogSource log) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown RecipeConfig val = new RecipeConfig { Name = recipeName, Item = item, Amount = 1, CraftingStation = (string.IsNullOrWhiteSpace(station) ? null : station.Trim()), MinStationLevel = Math.Max(1, stationLevel), Requirements = requirements }; ItemManager.Instance.AddRecipe(new CustomRecipe(val)); log.LogInfo((object)("Registered " + recipeName + " for " + item + ".")); } private static void ApplyItemType(string prefabName, ManualLogSource log) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { log.LogWarning((object)("Vanilla item " + prefabName + " was not found; it was not converted to a Utility item.")); return; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { log.LogWarning((object)("Vanilla item " + prefabName + " has no usable ItemDrop data.")); return; } if (prefabName == "IceShoes") { component.m_itemData.m_shared.m_name = "$item_iceshoes"; component.m_itemData.m_shared.m_description = "$item_iceshoes_description"; } else if (prefabName == "IceSkates") { component.m_itemData.m_shared.m_name = "$item_iceskates"; component.m_itemData.m_shared.m_description = "$item_iceskates_description"; } component.m_itemData.m_shared.m_itemType = (ItemType)18; component.m_itemData.m_shared.m_armor = 0f; component.m_itemData.m_shared.m_armorPerLevel = 0f; component.m_itemData.m_shared.m_useDurability = false; component.m_itemData.m_shared.m_canBeReparied = false; component.m_itemData.m_shared.m_maxDurability = 0f; component.m_itemData.m_shared.m_durabilityPerLevel = 0f; component.m_itemData.m_shared.m_maxQuality = 1; } } internal static class ModConfig { internal static ConfigEntry<bool> IceSpikesCraftEnabled; internal static ConfigEntry<bool> IceSpikesHaldorEnabled; internal static ConfigEntry<int> IceSpikesHaldorPrice; internal static ConfigEntry<int> IceSpikesHaldorStack; internal static ConfigEntry<string> IceSpikesHaldorGlobalKey; internal static ConfigEntry<string> IceSpikesStation; internal static ConfigEntry<int> IceSpikesStationLevel; internal static ConfigEntry<string> IceSpikesIngredients; internal static ConfigEntry<bool> IceSkatesCraftEnabled; internal static ConfigEntry<bool> IceSkatesHaldorEnabled; internal static ConfigEntry<int> IceSkatesHaldorPrice; internal static ConfigEntry<int> IceSkatesHaldorStack; internal static ConfigEntry<string> IceSkatesHaldorGlobalKey; internal static ConfigEntry<string> IceSkatesStation; internal static ConfigEntry<int> IceSkatesStationLevel; internal static ConfigEntry<string> IceSkatesIngredients; internal static void Bind(ConfigFile config) { IceSpikesCraftEnabled = config.Bind<bool>("Ice Spikes", "Craftable", true, "Add a crafting recipe for the vanilla IceShoes item."); IceSpikesHaldorEnabled = config.Bind<bool>("Ice Spikes", "Sold by Haldor", false, "Add IceShoes to vanilla Haldor's stock."); IceSpikesHaldorPrice = config.Bind<int>("Ice Spikes", "Haldor price", 1000, "Coin price when Ice Spikes are sold by Haldor."); IceSpikesHaldorStack = config.Bind<int>("Ice Spikes", "Haldor amount", 1, "Amount sold per purchase."); IceSpikesHaldorGlobalKey = config.Bind<string>("Ice Spikes", "Haldor progression key", "defeated_fader", "Global key required before Haldor offers Ice Spikes. Empty disables the progression gate."); IceSpikesStation = config.Bind<string>("Ice Spikes", "Crafting station", "piece_workbench", "Station prefab ID; use an empty value for hand crafting."); IceSpikesStationLevel = config.Bind<int>("Ice Spikes", "Crafting station level", 5, "Required station level."); IceSpikesIngredients = config.Bind<string>("Ice Spikes recipe", "Ingredients", "MoleClaws:6,Frostwood:6,Leatherstraps:2", "Complete recipe ingredient list as comma-separated prefab ID:amount pairs, for example MoleClaws:6,Frostwood:6,Leatherstraps:2."); IceSkatesCraftEnabled = config.Bind<bool>("Ice Skates", "Craftable", false, "Add a crafting recipe for the vanilla IceSkates item."); IceSkatesHaldorEnabled = config.Bind<bool>("Ice Skates", "Sold by Haldor", true, "Add IceSkates to vanilla Haldor's stock."); IceSkatesHaldorPrice = config.Bind<int>("Ice Skates", "Haldor price", 1000, "Coin price when IceSkates are sold by Haldor."); IceSkatesHaldorStack = config.Bind<int>("Ice Skates", "Haldor amount", 1, "Amount sold per purchase."); IceSkatesHaldorGlobalKey = config.Bind<string>("Ice Skates", "Haldor progression key", "defeated_fader", "Global key required before Haldor offers IceSkates. Empty disables the progression gate. Use a Valheim global key, including keys added by other mods."); IceSkatesStation = config.Bind<string>("Ice Skates", "Crafting station", "piece_workbench", "Station prefab ID; use an empty value for hand crafting."); IceSkatesStationLevel = config.Bind<int>("Ice Skates", "Crafting station level", 5, "Required station level."); IceSkatesIngredients = config.Bind<string>("Ice Skates recipe", "Ingredients", "SealHide:6,NornThread:4,Leatherstraps:2", "Complete recipe ingredient list as comma-separated prefab ID:amount pairs, for example SealHide:6,NornThread:4,Leatherstraps:2."); } } [BepInPlugin("mythica.deepnorthutilityitems", "Deep North Utility Items", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "mythica.deepnorthutilityitems"; public const string PluginName = "Deep North Utility Items"; public const string PluginVersion = "1.0.0"; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "item_iceshoes"; localization.AddTranslation(ref text, "Ice Spikes"); text = "item_iceshoes_description"; localization.AddTranslation(ref text, "The spikes grip icy surfaces, stopping you from slipping on ice."); text = "item_iceskates"; localization.AddTranslation(ref text, "Ice Skates"); text = "item_iceskates_description"; localization.AddTranslation(ref text, "The blades slide on icy surfaces, increasing your speed and ability to turn on ice."); _harmony = new Harmony("mythica.deepnorthutilityitems"); _harmony.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += RegisterRecipes; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Deep North Utility Items 1.0.0 loaded."); } private void RegisterRecipes() { ItemIntegration.Register(((BaseUnityPlugin)this).Logger); } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterRecipes; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(VisEquipment), "AttachArmor", new Type[] { typeof(int), typeof(int), typeof(int) })] internal static class UtilityVisualSuppressor { private const string IceSpikesPrefab = "IceShoes"; private const string IceSkatesPrefab = "IceSkates"; private static readonly List<GameObject> NoVisuals = new List<GameObject>(); [HarmonyPrefix] private static bool Prefix(int itemHash, ref List<GameObject> __result) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return true; } GameObject itemPrefab = instance.GetItemPrefab(itemHash); if ((Object)(object)itemPrefab == (Object)null || (((Object)itemPrefab).name != "IceShoes" && ((Object)itemPrefab).name != "IceSkates")) { return true; } __result = NoVisuals; return false; } } }