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 HammerUpgrades v1.0.1
plugins/HammerUpgrades/HammerUpgrades.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; 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 Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Hammer Upgrades")] [assembly: AssemblyDescription("Quality-based upgrades for Valheim's vanilla Hammer.")] [assembly: AssemblyCompany("LEGIOmods")] [assembly: AssemblyProduct("Hammer Upgrades")] [assembly: AssemblyCopyright("HammerUpgrades by LEGIOmods, Copyright 2026.")] [assembly: ComVisible(false)] [assembly: Guid("e4473c9c-3aaa-47d7-8e30-95a6ed132292")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI for code, localization, documentation, and package preparation.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "OpenAI")] [assembly: AssemblyMetadata("AI_Agent", "OpenAI Codex")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.1.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 HammerUpgrades { [BepInPlugin("domen.valheim.hammerupgrades", "Hammer Upgrades", "1.0.1")] public sealed class HammerUpgradesPlugin : BaseUnityPlugin { public const string PluginGuid = "domen.valheim.hammerupgrades"; public const string PluginName = "Hammer Upgrades"; public const string PluginVersion = "1.0.1"; private Harmony harmony; internal static HammerUpgradesPlugin Instance { get; private set; } internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; internal HammerUpgradeConfig Settings { get; private set; } private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown Instance = this; try { Settings = new HammerUpgradeConfig(((BaseUnityPlugin)this).Config); HammerUpgradeSystem.Initialize(Settings, ((BaseUnityPlugin)this).Logger); harmony = new Harmony("domen.valheim.hammerupgrades"); harmony.PatchAll(typeof(HammerUpgradesPlugin).Assembly); if ((Object)(object)ObjectDB.instance != (Object)null) { HammerUpgradeSystem.Configure(ObjectDB.instance); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hammer Upgrades 1.0.1 initialized."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"Hammer Upgrades 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(); } HammerUpgradeSystem.Reset(); if (Instance == this) { Instance = null; } } } internal sealed class HammerUpgradeConfig { internal ConfigEntry<float> AreaRepairRadiusQ3 { get; } internal ConfigEntry<float> AreaRepairRadiusQ4 { get; } internal ConfigEntry<float> AreaRepairStaminaCostPerPiece { get; } internal ConfigEntry<float> Q4BuildStaminaMultiplier { get; } internal ConfigEntry<float> Q4RepairStaminaMultiplier { get; } internal HammerUpgradeConfig(ConfigFile config) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown AreaRepairRadiusQ3 = config.Bind<float>("Area Repair", "AreaRepairRadiusQ3", 5f, new ConfigDescription("Radius in meters for quality-3 area repair. / Radius in Metern für die Flächenreparatur auf Qualitätsstufe 3.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); AreaRepairRadiusQ4 = config.Bind<float>("Area Repair", "AreaRepairRadiusQ4", 15f, new ConfigDescription("Radius in meters for quality-4 area repair. / Radius in Metern für die Flächenreparatur auf Qualitätsstufe 4.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); AreaRepairStaminaCostPerPiece = config.Bind<float>("Area Repair", "AreaRepairStaminaCostPerPiece", 0f, new ConfigDescription("Stamina per additional piece. 0 uses Valheim's current Hammer build/repair cost. / Ausdauer je zusätzlichem Bauteil. 0 verwendet Valheims aktuelle Hammer-Bau-/Reparaturkosten.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); Q4BuildStaminaMultiplier = config.Bind<float>("Quality 4", "Q4BuildStaminaMultiplier", 0.5f, new ConfigDescription("Multiplier for quality-4 Hammer placement stamina. / Multiplikator für die Bauausdauer des Hammers auf Qualitätsstufe 4.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); Q4RepairStaminaMultiplier = config.Bind<float>("Quality 4", "Q4RepairStaminaMultiplier", 0.5f, new ConfigDescription("Multiplier for quality-4 additional area-repair stamina. / Multiplikator für zusätzliche Flächenreparaturen auf Qualitätsstufe 4.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); } } internal static class HammerUpgradeSystem { private sealed class DirectRepairContext { internal Player Player { get; } internal ItemData Tool { get; } internal Piece TargetPiece { get; } internal WearNTear TargetWear { get; } internal bool DirectRepairSucceeded { get; set; } internal DirectRepairContext(Player player, ItemData tool, Piece targetPiece, WearNTear targetWear) { Player = player; Tool = tool; TargetPiece = targetPiece; TargetWear = targetWear; } } internal const string HammerPrefabName = "Hammer"; private static readonly string[] UpgradeResourceNames = new string[6] { "Wood", "Stone", "RoundLog", "FineWood", "YmirRemains", "YggdrasilWood" }; private static readonly Dictionary<Requirement, string> HammerRequirements = new Dictionary<Requirement, string>(); private static readonly MethodInfo GetRightItemMethod = AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null); private static readonly MethodInfo GetBuildStaminaMethod = AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null); private static readonly MethodInfo CheckCanRemovePieceMethod = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", (Type[])null, (Type[])null); private static HammerUpgradeConfig settings; private static ManualLogSource log; private static SharedData hammerSharedData; private static Recipe hammerRecipe; private static bool isConfigured; private static bool configurationLogged; [ThreadStatic] private static DirectRepairContext directRepairContext; internal static void Initialize(HammerUpgradeConfig config, ManualLogSource logger) { if (GetRightItemMethod == null || GetBuildStaminaMethod == null || CheckCanRemovePieceMethod == null) { throw new MissingMethodException("Valheim 1.0.12 Hammer bindings changed: GetRightItem, GetBuildStamina, or CheckCanRemovePiece is missing."); } settings = config; log = logger; } internal static void Reset() { HammerRequirements.Clear(); hammerSharedData = null; hammerRecipe = null; isConfigured = false; directRepairContext = null; configurationLogged = false; } internal static bool Configure(ObjectDB objectDatabase) { //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown HammerRequirements.Clear(); hammerSharedData = null; hammerRecipe = null; isConfigured = false; if ((Object)(object)objectDatabase == (Object)null) { return false; } GameObject itemPrefab = objectDatabase.GetItemPrefab("Hammer"); ItemDrop hammerDrop = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>()); if ((Object)(object)hammerDrop == (Object)null) { ManualLogSource obj = log; if (obj != null) { obj.LogDebug((object)"Vanilla Hammer prefab is not available in this ObjectDB yet; configuration deferred."); } return false; } Recipe val = ((IEnumerable<Recipe>)objectDatabase.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe candidate) => (Object)(object)candidate != (Object)null && (Object)(object)candidate.m_item != (Object)null && (candidate.m_item == hammerDrop || ((Object)((Component)candidate.m_item).gameObject).name == "Hammer"))); if ((Object)(object)val == (Object)null) { ManualLogSource obj2 = log; if (obj2 != null) { obj2.LogError((object)"Vanilla recipe for prefab 'Hammer' was not found; upgrades remain disabled."); } return false; } Dictionary<string, ItemDrop> dictionary = new Dictionary<string, ItemDrop>(StringComparer.Ordinal); string[] upgradeResourceNames = UpgradeResourceNames; foreach (string text in upgradeResourceNames) { GameObject itemPrefab2 = objectDatabase.GetItemPrefab(text); ItemDrop val2 = (((Object)(object)itemPrefab2 == (Object)null) ? null : itemPrefab2.GetComponent<ItemDrop>()); if ((Object)(object)val2 == (Object)null) { ManualLogSource obj3 = log; if (obj3 != null) { obj3.LogError((object)("Required vanilla resource prefab '" + text + "' was not found; upgrades remain disabled.")); } return false; } dictionary.Add(text, val2); } if ((Object)(object)val.m_repairStation == (Object)null || ((Object)((Component)val.m_repairStation).gameObject).name != "piece_workbench") { ManualLogSource obj4 = log; if (obj4 != null) { obj4.LogError((object)"The vanilla Hammer recipe does not reference 'piece_workbench' as its upgrade/repair station; upgrades remain disabled."); } return false; } List<Requirement> list = ((val.m_resources == null) ? new List<Requirement>() : val.m_resources.Where((Requirement requirement) => requirement != null).ToList()); upgradeResourceNames = UpgradeResourceNames; foreach (string resourceName in upgradeResourceNames) { if (list.All((Requirement requirement) => GetRequirementResourceName(requirement) != resourceName)) { list.Add(new Requirement { m_resItem = dictionary[resourceName], m_amount = 0, m_amountPerLevel = 0, m_extraAmountOnlyOneIngredient = 0, m_upgraderResource = false, m_recover = true }); } } hammerDrop.m_itemData.m_shared.m_maxQuality = 4; val.m_minStationLevel = 1; val.m_resources = list.ToArray(); hammerSharedData = hammerDrop.m_itemData.m_shared; hammerRecipe = val; HammerRequirements.Clear(); foreach (Requirement item in list) { string requirementResourceName = GetRequirementResourceName(item); if (UpgradeResourceNames.Contains(requirementResourceName)) { HammerRequirements[item] = requirementResourceName; } } isConfigured = true; if (!configurationLogged) { configurationLogged = true; ManualLogSource obj5 = log; if (obj5 != null) { obj5.LogInfo((object)"Configured vanilla Hammer quality 1-4, exact upgrade costs, durability tiers, and area repair."); } } return true; } internal static bool IsVanillaHammer(ItemData item) { if (!isConfigured || item == null || item.m_shared == null) { return false; } if (item.m_shared == hammerSharedData) { return true; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name == "Hammer"; } return false; } internal static bool IsHammerRecipe(Recipe recipe) { if (!isConfigured || (Object)(object)recipe == (Object)null) { return false; } if (recipe == hammerRecipe) { return true; } if ((Object)(object)recipe.m_item != (Object)null) { return ((Object)((Component)recipe.m_item).gameObject).name == "Hammer"; } return false; } internal static bool TryGetUpgradeAmount(Requirement requirement, int quality, out int amount) { amount = 0; if (quality <= 1 || requirement == null || !HammerRequirements.TryGetValue(requirement, out var value)) { return false; } switch (quality) { case 2: amount = ((value == "Wood") ? 5 : ((value == "Stone") ? 2 : 0)); return true; case 3: amount = ((value == "RoundLog") ? 2 : ((value == "FineWood") ? 1 : 0)); return true; case 4: amount = ((value == "YmirRemains") ? 1 : ((value == "YggdrasilWood") ? 2 : 0)); return true; default: return true; } } internal static bool TryGetHammerDurability(ItemData item, int quality, out float durability) { durability = 0f; if (!IsVanillaHammer(item)) { return false; } switch (quality) { case 2: durability = 300f; return true; case 3: durability = 500f; return true; case 4: durability = 1000f; return true; default: return false; } } internal static int GetHammerStationLevel(int quality) { return quality switch { 2 => 2, 3 => 3, 4 => 5, _ => 1, }; } internal static string AppendUpgradeTooltip(ItemData item, int quality, string tooltip) { if (!IsVanillaHammer(item) || quality < 1 || quality > 4) { return tooltip; } bool flag = Localization.instance != null && string.Equals(Localization.instance.GetSelectedLanguage(), "German", StringComparison.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder(tooltip ?? string.Empty); if (stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] != '\n') { stringBuilder.AppendLine(); } stringBuilder.AppendLine(); stringBuilder.AppendLine(flag ? "<color=orange>Hammer-Upgrades:</color>" : "<color=orange>Hammer upgrades:</color>"); switch (quality) { case 1: stringBuilder.Append(flag ? "Vanilla-Verhalten" : "Vanilla behavior"); break; case 2: stringBuilder.Append(flag ? "Maximale Haltbarkeit: <color=orange>300</color>" : "Maximum durability: <color=orange>300</color>"); break; case 3: stringBuilder.AppendLine(flag ? "Maximale Haltbarkeit: <color=orange>500</color>" : "Maximum durability: <color=orange>500</color>"); stringBuilder.AppendFormat(flag ? "Flächenreparatur: <color=orange>{0:0.#} m</color>\n" : "Area repair: <color=orange>{0:0.#} m</color>\n", settings.AreaRepairRadiusQ3.Value); stringBuilder.Append(flag ? "Reparatur ohne nahe Werkstation" : "Repairs without a nearby crafting station"); break; case 4: stringBuilder.AppendLine(flag ? "Maximale Haltbarkeit: <color=orange>1000</color>" : "Maximum durability: <color=orange>1000</color>"); stringBuilder.AppendFormat(flag ? "Flächenreparatur: <color=orange>{0:0.#} m</color>\n" : "Area repair: <color=orange>{0:0.#} m</color>\n", settings.AreaRepairRadiusQ4.Value); stringBuilder.AppendLine(flag ? "Reparatur ohne nahe Werkstation" : "Repairs without a nearby crafting station"); stringBuilder.AppendFormat(flag ? "Bau-Ausdauerverbrauch: <color=orange>{0:0.#} %</color>\n" : "Building stamina use: <color=orange>{0:0.#}%</color>\n", settings.Q4BuildStaminaMultiplier.Value * 100f); stringBuilder.AppendFormat(flag ? "Flächenreparatur-Ausdauerverbrauch: <color=orange>{0:0.#} %</color>" : "Area-repair stamina use: <color=orange>{0:0.#}%</color>", settings.Q4RepairStaminaMultiplier.Value * 100f); break; } return stringBuilder.ToString(); } internal static bool IsQualityFourPlacement(Player player) { if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !((Character)player).InPlaceMode()) { return false; } ItemData rightItem = GetRightItem(player); if (!IsVanillaHammer(rightItem) || rightItem.m_quality != 4) { return false; } Piece selectedPiece = player.GetSelectedPiece(); if ((Object)(object)selectedPiece != (Object)null && !selectedPiece.m_repairPiece) { return !selectedPiece.m_removePiece; } return false; } internal static float ApplyBuildStaminaMultiplier(Player player, float stamina) { if (!IsQualityFourPlacement(player)) { return stamina; } return stamina * settings.Q4BuildStaminaMultiplier.Value; } internal static bool HavePlacementStamina(Character character, float vanillaRequirement) { Player player = (Player)(object)((character is Player) ? character : null); if (IsQualityFourPlacement(player)) { return character.HaveStamina(GetBuildStamina(player)); } return character.HaveStamina(vanillaRequirement); } internal static void BeginDirectRepair(Player player, ItemData tool) { directRepairContext = null; if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && IsVanillaHammer(tool) && tool.m_quality >= 3 && tool.m_quality <= 4) { Piece hoveringPiece = player.GetHoveringPiece(); WearNTear val = (((Object)(object)hoveringPiece == (Object)null) ? null : ((Component)hoveringPiece).GetComponent<WearNTear>()); if (!((Object)(object)val == (Object)null)) { directRepairContext = new DirectRepairContext(player, tool, hoveringPiece, val); } } } internal static bool CanRepairPieceWithoutStation(Player player, Piece piece) { if (!CanUseStationlessHammerRepair(player, piece)) { return CheckCanRemovePiece(player, piece); } return true; } internal static void ObserveWearNTearRepair(WearNTear wear, bool repaired) { DirectRepairContext directRepairContext = HammerUpgradeSystem.directRepairContext; if (repaired && directRepairContext != null && directRepairContext.TargetWear == wear) { directRepairContext.DirectRepairSucceeded = true; } } internal static void CompleteDirectRepair(Player player) { DirectRepairContext directRepairContext = HammerUpgradeSystem.directRepairContext; HammerUpgradeSystem.directRepairContext = null; if (directRepairContext == null || !directRepairContext.DirectRepairSucceeded || directRepairContext.Player != player) { return; } try { RepairArea(directRepairContext); } catch (Exception ex) { ManualLogSource obj = log; if (obj != null) { obj.LogError((object)"Area repair failed after a successful vanilla repair."); } ManualLogSource obj2 = log; if (obj2 != null) { obj2.LogError((object)ex); } } } internal static void CancelDirectRepair() { directRepairContext = null; } private static void RepairArea(DirectRepairContext context) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) int quality = context.Tool.m_quality; float num = ((quality == 3) ? settings.AreaRepairRadiusQ3.Value : settings.AreaRepairRadiusQ4.Value); if (num <= 0f) { return; } Vector3 center = ((Component)context.TargetPiece).transform.position; List<Piece> list = new List<Piece>(); Piece.GetAllPiecesInRadius(center, num, list); list.Sort((Piece left, Piece right) => DistanceSquared(left, center).CompareTo(DistanceSquared(right, center))); float value = settings.AreaRepairStaminaCostPerPiece.Value; float num2 = ((value > 0f) ? value : GetBuildStamina(context.Player)); float num3 = ((quality == 4) ? (num2 * settings.Q4RepairStaminaMultiplier.Value) : num2); num3 = Mathf.Max(0f, num3); int num4 = 0; foreach (Piece item in list) { if (CanAreaRepair(context, item, out var wear)) { if (!((Character)context.Player).HaveStamina(num3)) { break; } if (wear.Repair()) { ((Character)context.Player).UseStamina(num3); CreateRepairEffect(item, context.Player); num4++; } } } ShowAreaRepairMessage(context.Player, num4); } private static void CreateRepairEffect(Piece piece, Player player) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)piece == (Object)null) && !((Object)(object)player == (Object)null) && piece.m_placeEffect != null) { piece.m_placeEffect.Create(((Component)piece).transform.position, ((Component)piece).transform.rotation, (Transform)null, 1f, -1, ((Character)player).GetZDOID()); } } private static void ShowAreaRepairMessage(Player player, int repairedPieces) { string text = ((Localization.instance != null && string.Equals(Localization.instance.GetSelectedLanguage(), "German", StringComparison.OrdinalIgnoreCase)) ? $"Flächenreparatur: {repairedPieces} zusätzliche Bauteile repariert" : $"Area repair: repaired {repairedPieces} additional pieces"); ((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false); } private static bool CanAreaRepair(DirectRepairContext context, Piece candidate, out WearNTear wear) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) wear = null; if ((Object)(object)candidate == (Object)null || candidate == context.TargetPiece || !candidate.IsPlacedByPlayer()) { return false; } wear = ((Component)candidate).GetComponent<WearNTear>(); if ((Object)(object)wear == (Object)null || wear.GetHealthPercentage() >= 1f) { return false; } if (!PrivateArea.CheckAccess(((Component)candidate).transform.position, 0f, false, false)) { return false; } return CanRepairPieceWithoutStation(context.Player, candidate); } private static bool CanUseStationlessHammerRepair(Player player, Piece piece) { if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null || !piece.IsPlacedByPlayer()) { return false; } ItemData rightItem = GetRightItem(player); if (IsVanillaHammer(rightItem) && rightItem.m_quality >= 3) { return rightItem.m_quality <= 4; } return false; } private static float DistanceSquared(Piece piece, Vector3 center) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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) if (!((Object)(object)piece == (Object)null)) { Vector3 val = ((Component)piece).transform.position - center; return ((Vector3)(ref val)).sqrMagnitude; } return float.MaxValue; } private static string GetRequirementResourceName(Requirement requirement) { if (!((Object)(object)requirement?.m_resItem == (Object)null)) { return ((Object)((Component)requirement.m_resItem).gameObject).name; } return string.Empty; } private static ItemData GetRightItem(Player player) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return (ItemData)GetRightItemMethod.Invoke(player, null); } private static float GetBuildStamina(Player player) { return (float)GetBuildStaminaMethod.Invoke(player, null); } private static bool CheckCanRemovePiece(Player player, Piece piece) { return (bool)CheckCanRemovePieceMethod.Invoke(player, new object[1] { piece }); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDbAwakePatch { private static void Postfix(ObjectDB __instance) { HammerUpgradeSystem.Configure(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDbCopyPatch { private static void Postfix(ObjectDB __instance) { HammerUpgradeSystem.Configure(__instance); } } [HarmonyPatch(typeof(Requirement), "GetAmount")] internal static class HammerRequirementAmountPatch { private static bool Prefix(Requirement __instance, int __0, ref int __result) { if (!HammerUpgradeSystem.TryGetUpgradeAmount(__instance, __0, out var amount)) { return true; } __result = amount; return false; } } [HarmonyPatch(typeof(Recipe), "GetRequiredStationLevel")] internal static class HammerRequiredStationLevelPatch { private static bool Prefix(Recipe __instance, int __0, ref int __result) { if (!HammerUpgradeSystem.IsHammerRecipe(__instance)) { return true; } __result = HammerUpgradeSystem.GetHammerStationLevel(__0); return false; } } [HarmonyPatch(typeof(ItemData), "GetMaxDurability", new Type[] { typeof(int) })] internal static class HammerMaxDurabilityPatch { private static bool Prefix(ItemData __instance, int __0, ref float __result) { if (!HammerUpgradeSystem.TryGetHammerDurability(__instance, __0, out var durability)) { return true; } __result = durability; return false; } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class HammerTooltipPatch { private static void Postfix(ItemData __0, int __1, ref string __result) { __result = HammerUpgradeSystem.AppendUpgradeTooltip(__0, __1, __result); } } [HarmonyPatch(typeof(Player), "Repair")] internal static class PlayerRepairPatch { private static void Prefix(Player __instance, ItemData toolItem) { HammerUpgradeSystem.BeginDirectRepair(__instance, toolItem); } private static void Postfix(Player __instance) { HammerUpgradeSystem.CompleteDirectRepair(__instance); } private static Exception Finalizer(Exception __exception) { if (__exception != null) { HammerUpgradeSystem.CancelDirectRepair(); } return __exception; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", new Type[1] { typeof(Piece) }, (Type[])null); MethodInfo operand = AccessTools.Method(typeof(HammerUpgradeSystem), "CanRepairPieceWithoutStation", (Type[])null, (Type[])null); int num = 0; for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], methodInfo)) { list[i].opcode = OpCodes.Call; list[i].operand = operand; num++; } } if (num != 1) { throw new InvalidOperationException($"Expected one station check in Player.Repair, found {num}; refusing to alter repair behavior."); } return list; } } [HarmonyPatch(typeof(WearNTear), "Repair")] internal static class WearNTearRepairPatch { private static void Postfix(WearNTear __instance, bool __result) { HammerUpgradeSystem.ObserveWearNTearRepair(__instance, __result); } } [HarmonyPatch(typeof(Player), "GetBuildStamina")] internal static class HammerBuildStaminaCostPatch { private static void Postfix(Player __instance, ref float __result) { __result = HammerUpgradeSystem.ApplyBuildStaminaMultiplier(__instance, __result); } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] internal static class HammerBuildStaminaCheckPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(Character), "HaveStamina", new Type[1] { typeof(float) }, (Type[])null); MethodInfo operand = AccessTools.Method(typeof(HammerUpgradeSystem), "HavePlacementStamina", (Type[])null, (Type[])null); List<int> list2 = new List<int>(); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], methodInfo)) { list2.Add(i); } } if (list2.Count == 2) { int index = list2[1]; list[index].opcode = OpCodes.Call; list[index].operand = operand; return list; } throw new InvalidOperationException($"Expected two stamina checks in Player.UpdatePlacement, found {list2.Count}; refusing to apply a partial Hammer stamina patch."); } } }