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 MegingjordUpgrades v1.0.2
plugins/MegingjordUpgrades/MegingjordUpgrades.dll
Decompiled 14 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("MegingjordUpgrades")] [assembly: AssemblyDescription("Adds quality upgrades to Valheim's vanilla Megingjord.")] [assembly: AssemblyCompany("LEGIOmods")] [assembly: AssemblyProduct("MegingjordUpgrades")] [assembly: AssemblyCopyright("Copyright 2026 LEGIOmods")] [assembly: ComVisible(false)] [assembly: Guid("b2a1c4d7-4f20-4d8b-9e11-8a5b7c6d2f40")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with assistance from Microsoft Copilot for code, localization, documentation, and package preparation.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Microsoft")] [assembly: AssemblyMetadata("AI_Agent", "Microsoft Copilot")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.2.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 MegingjordUpgrades { [BepInPlugin("domen.valheim.megingjordupgrades", "MegingjordUpgrades", "1.0.2")] public sealed class MegingjordUpgradesPlugin : BaseUnityPlugin { public const string PluginGuid = "domen.valheim.megingjordupgrades"; public const string PluginName = "MegingjordUpgrades"; public const string PluginVersion = "1.0.2"; private Harmony harmony; internal static MegingjordUpgradesPlugin Instance { get; private set; } internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Instance = this; try { MegingjordUpgradeSystem.Initialize(((BaseUnityPlugin)this).Logger); harmony = new Harmony("domen.valheim.megingjordupgrades"); harmony.PatchAll(typeof(MegingjordUpgradesPlugin).Assembly); if ((Object)(object)ObjectDB.instance != (Object)null) { MegingjordUpgradeSystem.Configure(ObjectDB.instance); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"MegingjordUpgrades 1.0.2 initialized."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"MegingjordUpgrades could not be initialized."); ((BaseUnityPlugin)this).Logger.LogError((object)ex); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } MegingjordUpgradeSystem.Reset(); if (Instance == this) { Instance = null; } } } internal static class MegingjordUpgradeSystem { private sealed class MethodInfoHolder { private readonly MethodInfo method; internal MethodInfoHolder(Type type, string name) { method = AccessTools.Method(type, name, (Type[])null, (Type[])null); } internal object Invoke(object instance) { if (!(method == null)) { return method.Invoke(instance, null); } return null; } } private sealed class FieldInfoHolder { private readonly FieldInfo field; internal FieldInfoHolder(Type type, string name) { field = AccessTools.Field(type, name); } internal object GetValue(object instance) { if (!(field == null)) { return field.GetValue(instance); } return null; } } internal const string PrefabName = "BeltStrength"; private const string BeltQualityZdoKey = "domen.valheim.megingjordupgrades.beltQuality"; private const string VagonQualityZdoKey = "domen.valheim.megingjordupgrades.vagonQuality"; private const string VagonQualityRpcName = "RPC_MegingjordPullQuality"; private static readonly MethodInfoHolder GetInventoryMethod = new MethodInfoHolder(typeof(Player), "GetInventory"); private static readonly MethodInfoHolder GetEquippedItemsMethod = new MethodInfoHolder(typeof(Inventory), "GetEquippedItems"); private static readonly MethodInfoHolder UpdateVagonMassMethod = new MethodInfoHolder(typeof(Vagon), "UpdateMass"); private static readonly FieldInfoHolder AttachedObjectField = new FieldInfoHolder(typeof(Vagon), "m_attachedObject"); private static SharedData megingjordSharedData; private static Recipe megingjordRecipe; private static readonly Dictionary<Requirement, string> Requirements = new Dictionary<Requirement, string>(); private static bool isConfigured; private static ManualLogSource log; internal static void Initialize(ManualLogSource logger) { log = logger; } internal static void Reset() { megingjordSharedData = null; megingjordRecipe = null; Requirements.Clear(); isConfigured = false; } internal static bool Configure(ObjectDB objectDatabase) { megingjordSharedData = null; megingjordRecipe = null; Requirements.Clear(); isConfigured = false; GameObject val = ((objectDatabase != null) ? objectDatabase.GetItemPrefab("BeltStrength") : null); ItemDrop itemDrop = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>()); if ((Object)(object)itemDrop == (Object)null || itemDrop.m_itemData == null || itemDrop.m_itemData.m_shared == null) { return false; } itemDrop.m_itemData.m_shared.m_maxQuality = 4; Recipe val2 = objectDatabase.m_recipes.Find((Recipe candidate) => (Object)(object)candidate != (Object)null && (Object)(object)candidate.m_item != (Object)null && (candidate.m_item.m_itemData.m_shared == itemDrop.m_itemData.m_shared || ((Object)((Component)candidate.m_item).gameObject).name == "BeltStrength")); if ((Object)(object)val2 == (Object)null) { CraftingStation val3 = FindForge(objectDatabase); if ((Object)(object)val3 == (Object)null) { ManualLogSource obj = log; if (obj != null) { obj.LogWarning((object)"Vanilla Forge CraftingStation is not available yet; Megingjord upgrades will retry with the next ObjectDB setup."); } return false; } val2 = ScriptableObject.CreateInstance<Recipe>(); val2.m_item = itemDrop; val2.m_amount = 1; val2.m_enabled = true; val2.m_noCraftOnlyUpgrade = true; val2.m_craftingStation = val3; val2.m_repairStation = val3; val2.m_minStationLevel = 1; objectDatabase.m_recipes.Add(val2); } AddRequirement(objectDatabase, "DeerHide"); AddRequirement(objectDatabase, "Iron"); AddRequirement(objectDatabase, "YmirRemains"); AddRequirement(objectDatabase, "Silver"); AddRequirement(objectDatabase, "DragonTear"); AddRequirement(objectDatabase, "Eitr"); AddRequirement(objectDatabase, "YagluthDrop"); val2.m_resources = new List<Requirement>(Requirements.Keys).ToArray(); megingjordRecipe = val2; megingjordSharedData = itemDrop.m_itemData.m_shared; isConfigured = true; ManualLogSource obj2 = log; if (obj2 != null) { obj2.LogInfo((object)"Configured vanilla Megingjord 'BeltStrength' quality 1-4 with carry weights 150/200/250/400 and Forge upgrades."); } return true; } internal static bool IsMegingjord(ItemData item) { if (!isConfigured || item == null || item.m_shared == null) { return false; } if (item.m_shared != megingjordSharedData) { if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name == "BeltStrength"; } return false; } return true; } internal static bool IsRequirement(Requirement requirement, int quality, out int amount) { amount = 0; if (!isConfigured || requirement == null || !Requirements.TryGetValue(requirement, out var value) || quality <= 1) { return false; } switch (quality) { case 2: amount = value switch { "YmirRemains" => 5, "Iron" => 10, "DeerHide" => 5, _ => 0, }; return true; case 3: amount = value switch { "YmirRemains" => 5, "DragonTear" => 1, "Silver" => 10, _ => 0, }; return true; case 4: amount = value switch { "YmirRemains" => 5, "YagluthDrop" => 1, "Eitr" => 20, _ => 0, }; return true; default: return true; } } internal static bool IsRecipe(Recipe recipe) { if (isConfigured) { return recipe == megingjordRecipe; } return false; } internal static int GetStationLevel(int quality) { return quality switch { 2 => 2, 3 => 3, 4 => 5, _ => 1, }; } internal static float GetCarryWeight(int quality) { return quality switch { 2 => 200f, 3 => 250f, 4 => 400f, _ => 150f, }; } internal static string AppendUpgradeTooltip(ItemData item, int quality, string tooltip) { if (!IsMegingjord(item) || quality < 1 || quality > 4) { return tooltip; } bool flag = Localization.instance != null && string.Equals(Localization.instance.GetSelectedLanguage(), "German", StringComparison.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder(RemoveVanillaMegingjordDescription(tooltip, flag)); if (stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] != '\n') { stringBuilder.AppendLine(); } stringBuilder.AppendLine(); stringBuilder.AppendLine(flag ? "<color=orange>Megingjord-Upgrades:</color>" : "<color=orange>Megingjord upgrades:</color>"); switch (quality) { case 1: stringBuilder.Append(flag ? "Traglast: <color=orange>150</color>\nVanilla-Wagenverhalten" : "Carry weight: <color=orange>150</color>\nVanilla cart behavior"); break; case 2: stringBuilder.Append(flag ? "Traglast: <color=orange>200</color>\nUpgrade: <color=orange>5 Hirschleder, 10 Eisen, 5 Ymir-Fleisch</color>\nWagenlast: <color=orange>66 % weniger Gewichtseinfluss</color>" : "Carry weight: <color=orange>200</color>\nUpgrade: <color=orange>5 Deer Hide, 10 Iron, 5 Ymir Flesh</color>\nCart load: <color=orange>66% less weight influence</color>"); break; case 3: stringBuilder.Append(flag ? "Traglast: <color=orange>250</color>\nUpgrade: <color=orange>10 Silber, 1 Drachenträne, 5 Ymir-Fleisch</color>\nWagenlast: <color=orange>kein Gewichtseinfluss</color>" : "Carry weight: <color=orange>250</color>\nUpgrade: <color=orange>10 Silver, 1 Dragon Tear, 5 Ymir Flesh</color>\nCart load: <color=orange>no weight influence</color>"); break; case 4: stringBuilder.Append(flag ? "Traglast: <color=orange>400</color>\nUpgrade: <color=orange>20 Eitr, 1 Zerrissener Geist, 5 Ymir-Fleisch</color>\nWagenlast: <color=orange>kein Gewichtseinfluss</color>" : "Carry weight: <color=orange>400</color>\nUpgrade: <color=orange>20 Eitr, 1 Torn Spirit, 5 Ymir Flesh</color>\nCart load: <color=orange>no weight influence</color>"); break; } return stringBuilder.ToString(); } private static string RemoveVanillaMegingjordDescription(string tooltip, bool german) { if (string.IsNullOrEmpty(tooltip)) { return tooltip; } string[] array = tooltip.Replace("\r\n", "\n").Split(new char[1] { '\n' }); StringBuilder stringBuilder = new StringBuilder(tooltip.Length); for (int i = 0; i < array.Length; i++) { string text = array[i]; string text2 = text.Replace("<color=orange>", string.Empty).Replace("</color>", string.Empty).Trim(); bool flag = ((!german) ? (text2.IndexOf("Increases your maximum carry weight", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Max. Carry Weight:", StringComparison.OrdinalIgnoreCase) >= 0) : (text2.IndexOf("Erhöhe das max. Gewicht", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Max. Gewicht:", StringComparison.OrdinalIgnoreCase) >= 0)); if (!((i > 0 && (string.Equals(text2, "Megingjord", StringComparison.OrdinalIgnoreCase) || string.Equals(text2, "Megingjard", StringComparison.OrdinalIgnoreCase))) || flag)) { if (stringBuilder.Length > 0) { stringBuilder.Append('\n'); } stringBuilder.Append(text); } } return stringBuilder.ToString().TrimEnd(Array.Empty<char>()); } internal static ItemData GetBelt(Player player) { object obj = GetInventoryMethod.Invoke(player); Inventory val = (Inventory)((obj is Inventory) ? obj : null); if (val == null) { return null; } if (!(GetEquippedItemsMethod.Invoke(val) is List<ItemData> list)) { return null; } return list.Find(IsMegingjord); } internal static void SyncBeltQuality(Player player, ItemData belt = null) { if ((Object)(object)player == (Object)null) { return; } ZNetView component = ((Component)player).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner()) { if (belt == null) { belt = GetBelt(player); } int num = (IsMegingjord(belt) ? Mathf.Clamp(belt.m_quality, 1, 4) : 0); ZDO zDO = component.GetZDO(); if (zDO != null && zDO.GetInt("domen.valheim.megingjordupgrades.beltQuality", -1) != num) { zDO.Set("domen.valheim.megingjordupgrades.beltQuality", num); } } } internal static void RegisterVagonRpc(Vagon vagon) { ZNetView networkView = GetNetworkView(vagon); if (!((Object)(object)networkView == (Object)null) && networkView.IsValid()) { networkView.Register<int>("RPC_MegingjordPullQuality", (Action<long, int>)delegate(long sender, int quality) { ReceiveVagonPullQuality(vagon, sender, quality); }); } } internal static void RequestVagonPullQuality(Vagon vagon, Player player) { if ((Object)(object)vagon == (Object)null || (Object)(object)player == (Object)null) { return; } ItemData belt = GetBelt(player); int num = (IsMegingjord(belt) ? Mathf.Clamp(belt.m_quality, 1, 4) : 0); SyncBeltQuality(player, belt); ZNetView networkView = GetNetworkView(vagon); if (!((Object)(object)networkView == (Object)null) && networkView.IsValid()) { networkView.InvokeRPC("RPC_MegingjordPullQuality", new object[1] { num }); ManualLogSource obj = log; if (obj != null) { obj.LogInfo((object)$"Sent cart pull quality {num} to the current cart owner."); } } } internal static void ClearVagonPullQuality(Vagon vagon) { ZNetView networkView = GetNetworkView(vagon); if (!((Object)(object)networkView == (Object)null) && networkView.IsValid() && networkView.IsOwner() && !vagon.IsAttached()) { SetVagonQuality(networkView, 0); vagon.m_itemWeightMassFactor = 1f; } } internal static void RefreshVagonMass(Vagon vagon) { ApplyVagonPullSettings(vagon); UpdateVagonMassMethod.Invoke(vagon); } internal static void ApplyVagonPullSettings(Vagon vagon) { if ((Object)(object)vagon == (Object)null) { return; } ZNetView networkView = GetNetworkView(vagon); if (!vagon.IsAttached()) { vagon.m_itemWeightMassFactor = 1f; return; } object value = AttachedObjectField.GetValue(vagon); GameObject val = (GameObject)((value is GameObject) ? value : null); Player val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<Player>()); ItemData val3 = (((Object)(object)val2 == (Object)null) ? null : GetBelt(val2)); int num = (IsMegingjord(val3) ? val3.m_quality : GetSyncedBeltQuality(val2)); if ((num < 1 || num > 4) && (Object)(object)networkView != (Object)null && networkView.IsValid()) { ZDO zDO = networkView.GetZDO(); num = ((zDO != null) ? zDO.GetInt("domen.valheim.megingjordupgrades.vagonQuality", 0) : 0); } if (num < 1 || num > 4) { vagon.m_itemWeightMassFactor = 1f; return; } SyncBeltQuality(val2, val3); if ((Object)(object)networkView != (Object)null && networkView.IsValid() && networkView.IsOwner()) { SetVagonQuality(networkView, num); } switch (num) { case 1: vagon.m_itemWeightMassFactor = 1f / 3f; break; case 2: vagon.m_itemWeightMassFactor = 1f / 6f; break; case 3: case 4: vagon.m_itemWeightMassFactor = 0f; break; } } private static void ReceiveVagonPullQuality(Vagon vagon, long sender, int quality) { ZNetView networkView = GetNetworkView(vagon); if ((Object)(object)networkView == (Object)null || !networkView.IsValid() || !networkView.IsOwner()) { return; } quality = Mathf.Clamp(quality, 0, 4); if (!vagon.IsAttached()) { SetVagonQuality(networkView, quality); ManualLogSource obj = log; if (obj != null) { obj.LogInfo((object)$"Cart owner accepted pull quality {quality} from peer {sender}."); } } } private static void SetVagonQuality(ZNetView networkView, int quality) { ZDO zDO = networkView.GetZDO(); if (zDO != null && zDO.GetInt("domen.valheim.megingjordupgrades.vagonQuality", -1) != quality) { zDO.Set("domen.valheim.megingjordupgrades.vagonQuality", quality); } } private static ZNetView GetNetworkView(Vagon vagon) { if (!((Object)(object)vagon == (Object)null)) { return ((Component)vagon).GetComponent<ZNetView>(); } return null; } private static int GetSyncedBeltQuality(Player player) { if ((Object)(object)player == (Object)null) { return 0; } ZNetView component = ((Component)player).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component == (Object)null || !component.IsValid()) ? null : component.GetZDO()); if (val != null) { return val.GetInt("domen.valheim.megingjordupgrades.beltQuality", 0); } return 0; } private static void AddRequirement(ObjectDB objectDatabase, string resourceName) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0051: Expected O, but got Unknown GameObject itemPrefab = objectDatabase.GetItemPrefab(resourceName); ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Required vanilla resource prefab '" + resourceName + "' was not found."); } Requirements.Add(new Requirement { m_resItem = val, m_recover = true }, resourceName); } private static CraftingStation FindForge(ObjectDB objectDatabase) { foreach (Recipe recipe in objectDatabase.m_recipes) { if (!((Object)(object)recipe == (Object)null)) { CraftingStation val = recipe.m_repairStation ?? recipe.m_craftingStation; if ((Object)(object)val != (Object)null && (((Object)((Component)val).gameObject).name == "forge" || ((Object)((Component)val).gameObject).name == "piece_forge")) { return val; } } } foreach (GameObject item in objectDatabase.m_items) { CraftingStation val2 = (((Object)(object)item == (Object)null) ? null : item.GetComponent<CraftingStation>()); if ((Object)(object)val2 != (Object)null && (((Object)item).name == "forge" || ((Object)item).name == "piece_forge")) { return val2; } } string[] array = new string[2] { "forge", "piece_forge" }; foreach (string text in array) { GameObject itemPrefab = objectDatabase.GetItemPrefab(text); CraftingStation val3 = ((itemPrefab != null) ? itemPrefab.GetComponent<CraftingStation>() : null); if ((Object)(object)val3 != (Object)null) { return val3; } } return null; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDbAwakePatch { private static void Postfix(ObjectDB __instance) { MegingjordUpgradeSystem.Configure(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDbCopyPatch { private static void Postfix(ObjectDB __instance) { MegingjordUpgradeSystem.Configure(__instance); } } [HarmonyPatch(typeof(Player), "GetMaxCarryWeight")] internal static class CarryWeightPatch { private static void Postfix(Player __instance, ref float __result) { ItemData belt = MegingjordUpgradeSystem.GetBelt(__instance); MegingjordUpgradeSystem.SyncBeltQuality(__instance, belt); if (MegingjordUpgradeSystem.IsMegingjord(belt)) { __result = __result - 150f + MegingjordUpgradeSystem.GetCarryWeight(belt.m_quality); } } } [HarmonyPatch(typeof(Vagon), "Awake")] internal static class VagonAwakePatch { private static void Postfix(Vagon __instance) { MegingjordUpgradeSystem.RegisterVagonRpc(__instance); } } [HarmonyPatch(typeof(Vagon), "Interact")] internal static class VagonInteractPatch { private static void Prefix(Vagon __instance, Humanoid __0, bool __1) { if (!__1) { Player val = (Player)(object)((__0 is Player) ? __0 : null); if (val != null) { MegingjordUpgradeSystem.RequestVagonPullQuality(__instance, val); } } } } [HarmonyPatch(typeof(Vagon), "Detach")] internal static class VagonDetachPatch { private static void Postfix(Vagon __instance) { MegingjordUpgradeSystem.ClearVagonPullQuality(__instance); } } [HarmonyPatch(typeof(Vagon), "AttachTo")] internal static class VagonAttachPatch { private static void Postfix(Vagon __instance) { MegingjordUpgradeSystem.RefreshVagonMass(__instance); } } [HarmonyPatch(typeof(Vagon), "UpdateMass")] internal static class VagonMassPatch { private static void Prefix(Vagon __instance) { MegingjordUpgradeSystem.ApplyVagonPullSettings(__instance); } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class MegingjordTooltipPatch { private static void Postfix(ItemData __0, int __1, ref string __result) { __result = MegingjordUpgradeSystem.AppendUpgradeTooltip(__0, __1, __result); } } [HarmonyPatch(typeof(Requirement), "GetAmount")] internal static class RequirementAmountPatch { private static bool Prefix(Requirement __instance, int __0, ref int __result) { if (!MegingjordUpgradeSystem.IsRequirement(__instance, __0, out var amount)) { return true; } __result = amount; return false; } } [HarmonyPatch(typeof(Recipe), "GetRequiredStationLevel")] internal static class RequiredStationLevelPatch { private static bool Prefix(Recipe __instance, int __0, ref int __result) { if (!MegingjordUpgradeSystem.IsRecipe(__instance)) { return true; } __result = MegingjordUpgradeSystem.GetStationLevel(__0); return false; } } }