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 ChestUpgradeMod v1.2.1
ChestUpgradeMod.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; 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: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ChestUpgradeMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Upgrade Valheim chests in place with a keypress.")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ChestUpgradeMod")] [assembly: AssemblyTitle("ChestUpgradeMod")] [assembly: AssemblyVersion("1.1.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; } } } internal sealed class ConfigurationManagerAttributes { public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput); public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public CustomHotkeyDrawerFunc CustomHotkeyDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } namespace ChestUpgradeMod { [BepInPlugin("yumi.valheim.chestupgrade", "ChestUpgrade", "1.2.1")] public class ChestUpgradePlugin : BaseUnityPlugin { private class UpgradeRequirement { public string ItemPrefabName; public int Amount; } private class UpgradeRecipe { public string NextPrefabName; public List<UpgradeRequirement> Requirements; } [HarmonyPatch(typeof(Container), "GetHoverText")] private static class Container_GetHoverText_Patch { private static void Postfix(Container __instance, ref string __result) { //IL_0263: Unknown result type (might be due to invalid IL or missing references) if (!_showHoverText.Value || (Object)(object)Player.m_localPlayer == (Object)null) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } StringBuilder stringBuilder = new StringBuilder(__result); bool flag = false; if (_hammerReplaceEnabled.Value) { GameObject selectedHammerChestPrefab = GetSelectedHammerChestPrefab(Player.m_localPlayer); if ((Object)(object)selectedHammerChestPrefab != (Object)null && Utils.GetPrefabName(selectedHammerChestPrefab) != Utils.GetPrefabName(((Component)__instance).gameObject)) { Piece component2 = selectedHammerChestPrefab.GetComponent<Piece>(); string value = (((Object)(object)component2 != (Object)null && !string.IsNullOrEmpty(component2.m_name)) ? TryLocalize(component2.m_name) : Utils.GetPrefabName(selectedHammerChestPrefab)); stringBuilder.Append("\n[<color=yellow><b>Click</b></color>] Replace with ").Append(value); if ((Object)(object)component2 != (Object)null && component2.m_resources != null) { Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); Requirement[] resources = component2.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val.m_resItem == (Object)null)) { string name = ((Object)((Component)val.m_resItem).gameObject).name; int num = CountItem(inventory, name); string value2 = ((num >= val.m_amount) ? "#00ff00" : "#ff5555"); stringBuilder.Append("\n <color=").Append(value2).Append(">") .Append(GetItemDisplayName(name)) .Append(" ") .Append(num) .Append("/") .Append(val.m_amount) .Append("</color>"); } } } flag = true; } } if (!flag && _hotkeyUpgradeEnabled.Value) { UpgradeRecipe recipeFor = GetRecipeFor(__instance); if (recipeFor != null) { GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(recipeFor.NextPrefabName) : null); if ((Object)(object)val2 != (Object)null) { string value3 = recipeFor.NextPrefabName; Piece component3 = val2.GetComponent<Piece>(); if ((Object)(object)component3 != (Object)null && !string.IsNullOrEmpty(component3.m_name)) { value3 = TryLocalize(component3.m_name); } Inventory inventory2 = ((Humanoid)Player.m_localPlayer).GetInventory(); stringBuilder.Append("\n[<color=yellow><b>").Append(_upgradeKey.Value).Append("</b></color>] Upgrade to ") .Append(value3); foreach (UpgradeRequirement requirement in recipeFor.Requirements) { int num2 = CountItem(inventory2, requirement.ItemPrefabName); string value4 = ((num2 >= requirement.Amount) ? "#00ff00" : "#ff5555"); stringBuilder.Append("\n <color=").Append(value4).Append(">") .Append(GetItemDisplayName(requirement.ItemPrefabName)) .Append(" ") .Append(num2) .Append("/") .Append(requirement.Amount) .Append("</color>"); } } } } __result = stringBuilder.ToString(); } } public const string PluginGUID = "yumi.valheim.chestupgrade"; public const string PluginName = "ChestUpgrade"; public const string PluginVersion = "1.2.1"; private const string WoodChest = "piece_chest_wood"; private const string ReinforcedChest = "piece_chest"; private const string BlackMetalChest = "piece_chest_blackmetal"; private static readonly FieldInfo BuildPiecesField = AccessTools.Field(typeof(Player), "m_buildPieces"); private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); internal static ManualLogSource Log; private static ConfigEntry<KeyCode> _upgradeKey; private static ConfigEntry<bool> _showHoverText; private static ConfigEntry<bool> _hotkeyUpgradeEnabled; private static ConfigEntry<bool> _hammerReplaceEnabled; private static ConfigEntry<bool> _debugLogging; private static ConfigEntry<float> _replaceDetectRadius; private static ConfigEntry<bool> _refundOnDowngrade; private static ConfigEntry<string> _tier1Requirements; private static ConfigEntry<string> _tier2Requirements; private static readonly Dictionary<string, UpgradeRecipe> Upgrades = new Dictionary<string, UpgradeRecipe>(); private static readonly Dictionary<string, string> SharedNameCache = new Dictionary<string, string>(); private Harmony _harmony; private static float _lastDebugLogTime; private static MethodInfo _localizeMethod; private static object _localizationInstance; private static bool _localizationChecked; private static int GetChestTier(string prefabName) { return prefabName switch { "piece_chest_wood" => 1, "piece_chest" => 2, "piece_chest_blackmetal" => 3, _ => 0, }; } private void Awake() { //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_020d: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; _upgradeKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "UpgradeKey", (KeyCode)117, "Key to press while looking at a chest to upgrade it."); _showHoverText = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHoverText", true, "Show the upgrade key and the required materials on the chest hover text."); _hotkeyUpgradeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableHotkeyUpgrade", true, "Enable the original hover+hotkey upgrade (Wood -> Reinforced -> Black Metal using the Requirements below)."); _hammerReplaceEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableHammerReplace", true, "Enable replacing a hovered chest with whatever chest piece is currently selected on the Hammer, at the exact same spot, using that piece's own normal build cost. Works for upgrades AND downgrades; items that don't fit after a downgrade drop on the ground instead of being lost."); _debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Log hammer-replace detection state once a second, for troubleshooting. Turn off once things work."); _replaceDetectRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ReplaceDetectRadius", 0.5f, "How close (in meters) the placement ghost must be to an existing chest to trigger a replace instead of a normal placement. Keep this small — roughly one chest's own footprint — so it doesn't grab a different nearby chest."); _refundOnDowngrade = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RefundOnDowngrade", true, "When hammer-replacing a chest with a lower tier one (e.g. Black Metal -> Reinforced), drop the materials the OLD chest itself cost to build on the ground, since that value is being destroyed."); _tier1Requirements = ((BaseUnityPlugin)this).Config.Bind<string>("Requirements", "WoodToReinforced", "FineWood:10,Iron:2", "Materials to upgrade Wood Chest -> Reinforced Chest. Format: ItemPrefabName:Amount,ItemPrefabName:Amount"); _tier2Requirements = ((BaseUnityPlugin)this).Config.Bind<string>("Requirements", "ReinforcedToBlackMetal", "Wood:10,Tar:2,BlackMetal:6", "Materials to upgrade Reinforced Chest -> Black Metal Chest. Format: ItemPrefabName:Amount,ItemPrefabName:Amount"); _tier1Requirements.SettingChanged += delegate { BuildUpgradeTable(); }; _tier2Requirements.SettingChanged += delegate { BuildUpgradeTable(); }; BuildUpgradeTable(); if (BuildPiecesField == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find Player.m_buildPieces — hammer-replace feature will be disabled. Chain-based hotkey upgrade still works normally."); } if (PlacementGhostField == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find Player.m_placementGhost — hammer-replace feature will be disabled. Chain-based hotkey upgrade still works normally."); } _harmony = new Harmony("yumi.valheim.chestupgrade"); _harmony.PatchAll(typeof(ChestUpgradePlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} v{1} loaded. Upgrade key: {2}", "ChestUpgrade", "1.2.1", _upgradeKey.Value)); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static void BuildUpgradeTable() { Upgrades.Clear(); Upgrades["piece_chest_wood"] = new UpgradeRecipe { NextPrefabName = "piece_chest", Requirements = ParseRequirements(_tier1Requirements.Value) }; Upgrades["piece_chest"] = new UpgradeRecipe { NextPrefabName = "piece_chest_blackmetal", Requirements = ParseRequirements(_tier2Requirements.Value) }; } private static List<UpgradeRequirement> ParseRequirements(string raw) { List<UpgradeRequirement> list = new List<UpgradeRequirement>(); if (string.IsNullOrEmpty(raw)) { return list; } string[] array = raw.Split(','); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(':'); if (array2.Length == 2 && int.TryParse(array2[1].Trim(), out var result)) { list.Add(new UpgradeRequirement { ItemPrefabName = array2[0].Trim(), Amount = result }); } } return list; } private void Update() { //IL_0188: 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) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; if (_debugLogging.Value && Time.time - _lastDebugLogTime > 1f) { _lastDebugLogTime = Time.time; GameObject selectedHammerChestPrefab = GetSelectedHammerChestPrefab(localPlayer); Container targetContainer = GetTargetContainer(localPlayer); object? obj = PlacementGhostField?.GetValue(localPlayer); GameObject val = (GameObject)((obj is GameObject) ? obj : null); string text = (((Object)(object)val != (Object)null) ? ((object)val.transform.position/*cast due to .constrained prefix*/).ToString() : "n/a"); string text2 = ((object)((Component)localPlayer).transform.position/*cast due to .constrained prefix*/).ToString(); Log.LogInfo((object)string.Format("[DEBUG] InPlaceMode={0} selectedChestPrefab={1} containerNearGhost={2} ghostPos={3} playerPos={4} placementGhostFieldFound={5} buildPiecesFieldFound={6}", ((Character)localPlayer).InPlaceMode(), ((Object)(object)selectedHammerChestPrefab != (Object)null) ? ((Object)selectedHammerChestPrefab).name : "null", ((Object)(object)targetContainer != (Object)null) ? ((Object)targetContainer).name : "null", text, text2, PlacementGhostField != null, BuildPiecesField != null)); } if (_hammerReplaceEnabled.Value && ((Character)localPlayer).InPlaceMode() && ZInput.GetButtonDown("Attack")) { if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] Attack pressed while InPlaceMode=true, attempting replace."); } TryHammerReplaceOnClick(localPlayer); } if (!Input.GetKeyDown(_upgradeKey.Value) || IsUiBlocking()) { return; } GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); if (!((Object)(object)hoverObject == (Object)null)) { Container componentInParent = hoverObject.GetComponentInParent<Container>(); if (!((Object)(object)componentInParent == (Object)null) && _hotkeyUpgradeEnabled.Value) { TryUpgradeHoveredChest(localPlayer, componentInParent); } } } private static GameObject GetSelectedHammerChestPrefab(Player player) { if (BuildPiecesField == null) { return null; } object? value = BuildPiecesField.GetValue(player); PieceTable val = (PieceTable)((value is PieceTable) ? value : null); if ((Object)(object)val == (Object)null) { return null; } Piece selectedPiece = val.GetSelectedPiece(); if ((Object)(object)selectedPiece == (Object)null) { return null; } if ((Object)(object)((Component)selectedPiece).GetComponent<Container>() == (Object)null) { return null; } return ((Component)selectedPiece).gameObject; } private static Container GetTargetContainer(Player player, bool verbose = false) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) object? obj = PlacementGhostField?.GetValue(player); GameObject val = (GameObject)((obj is GameObject) ? obj : null); Camera main = Camera.main; if ((Object)(object)main != (Object)null) { RaycastHit[] array = Physics.RaycastAll(new Ray(((Component)main).transform.position, ((Component)main).transform.forward), 10f); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2; if (verbose && _debugLogging.Value) { List<string> list = new List<string>(); array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val2 = array2[num]; bool flag = (Object)(object)val != (Object)null && ((RaycastHit)(ref val2)).transform.IsChildOf(val.transform); list.Add(string.Format("{0}@{1:F2}{2}", ((Object)((RaycastHit)(ref val2)).collider).name, ((RaycastHit)(ref val2)).distance, flag ? "(ghost-self)" : "")); } Log.LogInfo((object)string.Format("[DEBUG] RaycastAll found {0} hits: [{1}]", array.Length, string.Join(", ", list))); } array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val3 = array2[num]; if ((Object)(object)val != (Object)null && ((RaycastHit)(ref val3)).transform.IsChildOf(val.transform)) { continue; } Container componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<Container>(); if ((Object)(object)componentInParent != (Object)null) { if (verbose && _debugLogging.Value) { Log.LogInfo((object)("[DEBUG] Raycast resolved container: " + ((Object)componentInParent).name)); } return componentInParent; } } } else if (verbose && _debugLogging.Value) { Log.LogInfo((object)"[DEBUG] Camera.main is null, skipping raycast."); } if ((Object)(object)val == (Object)null) { return null; } Vector3 position = val.transform.position; float value = _replaceDetectRadius.Value; Collider[] array3 = Physics.OverlapSphere(position, value); Container val4 = null; float num2 = float.MaxValue; Collider[] array4 = array3; foreach (Collider val5 in array4) { if (((Component)val5).transform.IsChildOf(val.transform)) { continue; } Container componentInParent2 = ((Component)val5).GetComponentInParent<Container>(); if (!((Object)(object)componentInParent2 == (Object)null)) { float num3 = Vector3.Distance(position, ((Component)componentInParent2).transform.position); if (num3 < num2) { num2 = num3; val4 = componentInParent2; } } } if (verbose && _debugLogging.Value) { Log.LogInfo((object)string.Format("[DEBUG] Fallback: ghost at {0}, radius={1}, closest container={2} dist={3}", position, value, ((Object)(object)val4 != (Object)null) ? ((Object)val4).name : "null", ((Object)(object)val4 != (Object)null) ? num2.ToString("F2") : "n/a")); } return val4; } private void TryHammerReplaceOnClick(Player player) { GameObject selectedHammerChestPrefab = GetSelectedHammerChestPrefab(player); if ((Object)(object)selectedHammerChestPrefab == (Object)null) { if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] No chest selected on hammer, letting click through normally."); } return; } Container targetContainer = GetTargetContainer(player, verbose: true); if ((Object)(object)targetContainer == (Object)null) { if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] No existing chest near the placement ghost, letting click through normally."); } return; } if (_debugLogging.Value) { string prefabName = Utils.GetPrefabName(((Component)targetContainer).gameObject); string prefabName2 = Utils.GetPrefabName(selectedHammerChestPrefab); Log.LogInfo((object)("[DEBUG] Replacing '" + prefabName + "' with '" + prefabName2 + "'.")); } TryReplaceWithHammerPiece(player, targetContainer, selectedHammerChestPrefab); } private static bool IsUiBlocking() { if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return true; } if (Console.IsVisible()) { return true; } if (TextInput.IsVisible()) { return true; } if (InventoryGui.IsVisible()) { return true; } if (Menu.IsVisible()) { return true; } return false; } private void TryUpgradeHoveredChest(Player player, Container container) { UpgradeRecipe recipeFor = GetRecipeFor(container); if (recipeFor == null) { ((Character)player).Message((MessageType)2, "This chest cannot be upgraded further.", 0, (Sprite)null, false); return; } if (container.IsInUse()) { ((Character)player).Message((MessageType)2, "That chest is in use.", 0, (Sprite)null, false); return; } GameObject prefab = ZNetScene.instance.GetPrefab(recipeFor.NextPrefabName); if ((Object)(object)prefab == (Object)null) { Log.LogError((object)("Upgrade target prefab '" + recipeFor.NextPrefabName + "' was not found in ZNetScene.")); ((Character)player).Message((MessageType)2, "Upgrade failed: target chest prefab missing.", 0, (Sprite)null, false); return; } Inventory inventory = ((Humanoid)player).GetInventory(); foreach (UpgradeRequirement requirement in recipeFor.Requirements) { int num = CountItem(inventory, requirement.ItemPrefabName); if (num < requirement.Amount) { ((Character)player).Message((MessageType)2, $"Missing {GetItemDisplayName(requirement.ItemPrefabName)} ({num}/{requirement.Amount})", 0, (Sprite)null, false); return; } } foreach (UpgradeRequirement requirement2 in recipeFor.Requirements) { RemoveItem(inventory, requirement2.ItemPrefabName, requirement2.Amount); } ReplaceChest(container, prefab, "Chest upgraded!"); } private void TryReplaceWithHammerPiece(Player player, Container oldContainer, GameObject newPrefab) { //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) string prefabName = Utils.GetPrefabName(((Component)oldContainer).gameObject); string prefabName2 = Utils.GetPrefabName(newPrefab); if (prefabName == prefabName2) { if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] Same prefab type, nothing to replace."); } return; } if (oldContainer.IsInUse()) { if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] Bailing: chest is in use."); } ((Character)player).Message((MessageType)2, "That chest is in use.", 0, (Sprite)null, false); return; } Piece component = newPrefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null || component.m_resources == null || component.m_resources.Length == 0) { if (_debugLogging.Value) { Log.LogInfo((object)string.Format("[DEBUG] Bailing: piece={0} resources={1}", component, (!((Object)(object)component != (Object)null)) ? "n/a" : component.m_resources?.Length.ToString())); } ((Character)player).Message((MessageType)2, "That piece has no build cost, can't replace with it.", 0, (Sprite)null, false); return; } Inventory inventory = ((Humanoid)player).GetInventory(); Requirement[] resources; if (_debugLogging.Value) { resources = component.m_resources; foreach (Requirement val in resources) { string text = (((Object)(object)val.m_resItem != (Object)null) ? ((Object)((Component)val.m_resItem).gameObject).name : "NULL_ITEM"); int num = (((Object)(object)val.m_resItem != (Object)null) ? CountItem(inventory, text) : (-1)); Log.LogInfo((object)$"[DEBUG] Requirement: {text} need={val.m_amount} have={num}"); } } resources = component.m_resources; foreach (Requirement val2 in resources) { if ((Object)(object)val2.m_resItem == (Object)null) { continue; } string name = ((Object)((Component)val2.m_resItem).gameObject).name; int num2 = CountItem(inventory, name); if (num2 < val2.m_amount) { if (_debugLogging.Value) { Log.LogInfo((object)$"[DEBUG] Bailing: missing {name} ({num2}/{val2.m_amount})."); } ((Character)player).Message((MessageType)2, $"Missing {GetItemDisplayName(name)} ({num2}/{val2.m_amount})", 0, (Sprite)null, false); return; } } resources = component.m_resources; foreach (Requirement val3 in resources) { if (!((Object)(object)val3.m_resItem == (Object)null)) { RemoveItem(inventory, ((Object)((Component)val3.m_resItem).gameObject).name, val3.m_amount); } } Piece component2 = newPrefab.GetComponent<Piece>(); string text2 = (((Object)(object)component2 != (Object)null && !string.IsNullOrEmpty(component2.m_name)) ? TryLocalize(component2.m_name) : prefabName2); if (GetChestTier(prefabName) > 0 && GetChestTier(prefabName2) > 0 && GetChestTier(prefabName2) < GetChestTier(prefabName) && _refundOnDowngrade.Value) { if (_debugLogging.Value) { Log.LogInfo((object)("[DEBUG] Downgrade detected (" + prefabName + " -> " + prefabName2 + "), refunding old chest's build cost.")); } RefundChestResources(prefabName, ((Component)oldContainer).transform.position, ((Component)oldContainer).transform.rotation); } if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] Requirements met, calling ReplaceChest."); } ReplaceChest(oldContainer, newPrefab, "Chest replaced with " + text2 + "!"); } private void RefundChestResources(string prefabName, Vector3 pos, Quaternion rot) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefabName) : null); Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null); if ((Object)(object)val2 == (Object)null || val2.m_resources == null) { return; } Requirement[] resources = val2.m_resources; foreach (Requirement val3 in resources) { if (!((Object)(object)val3.m_resItem == (Object)null)) { try { ItemData obj = val3.m_resItem.m_itemData.Clone(); obj.m_dropPrefab = ((Component)val3.m_resItem).gameObject; ItemDrop.DropItem(obj, val3.m_amount, pos + Vector3.up, rot); } catch (Exception arg) { Log.LogError((object)$"Failed to refund {((Object)((Component)val3.m_resItem).gameObject).name} on downgrade: {arg}"); } } } } private static UpgradeRecipe GetRecipeFor(Container container) { if ((Object)(object)container == (Object)null) { return null; } string prefabName = Utils.GetPrefabName(((Component)container).gameObject); if (!Upgrades.TryGetValue(prefabName, out var value)) { return null; } return value; } private void ReplaceChest(Container oldContainer, GameObject nextPrefab, string successMessage) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] ReplaceChest entered."); } ZNetView component = ((Component)oldContainer).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { Log.LogError((object)"Old chest has no valid ZNetView, aborting upgrade."); return; } component.ClaimOwnership(); Vector3 position = ((Component)oldContainer).transform.position; Quaternion rotation = ((Component)oldContainer).transform.rotation; Inventory inventory = oldContainer.GetInventory(); List<ItemData> list = new List<ItemData>(inventory.GetAllItems()); inventory.RemoveAll(); ZNetScene.instance.Destroy(((Component)oldContainer).gameObject); GameObject val = Object.Instantiate<GameObject>(nextPrefab, position, rotation); Container component2 = val.GetComponent<Container>(); if ((Object)(object)component2 == (Object)null) { Log.LogError((object)"Upgraded prefab has no Container component, aborting upgrade."); ZNetScene.instance.Destroy(val); return; } Piece component3 = val.GetComponent<Piece>(); if ((Object)(object)component3 != (Object)null) { EffectList placeEffect = component3.m_placeEffect; if (placeEffect != null) { placeEffect.Create(position, rotation, (Transform)null, 1f, -1, default(ZDOID)); } } Inventory inventory2 = component2.GetInventory(); foreach (ItemData item in list) { if (!inventory2.AddItem(item)) { ItemDrop.DropItem(item, item.m_stack, position + Vector3.up, rotation); } } ((Character)Player.m_localPlayer).Message((MessageType)2, successMessage, 0, (Sprite)null, false); if (_debugLogging.Value) { Log.LogInfo((object)"[DEBUG] ReplaceChest completed successfully."); } } private static string GetSharedName(string itemPrefabName) { if (SharedNameCache.TryGetValue(itemPrefabName, out var value)) { return value; } if ((Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemPrefabName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); string text = (((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_name : null); if (text != null) { SharedNameCache[itemPrefabName] = text; } return text; } internal static string GetItemDisplayName(string itemPrefabName) { return TryLocalize(GetSharedName(itemPrefabName) ?? itemPrefabName); } internal static string TryLocalize(string text) { if (string.IsNullOrEmpty(text)) { return text; } if (!_localizationChecked) { _localizationChecked = true; try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("Localization"); if (type == null) { continue; } object obj = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? type.GetField("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); if (obj != null) { MethodInfo method = type.GetMethod("Localize", new Type[1] { typeof(string) }); if (!(method == null)) { _localizationInstance = obj; _localizeMethod = method; break; } } } } catch (Exception ex) { Log.LogWarning((object)("Could not hook into Localization, names will show as raw tokens: " + ex.Message)); } } if (_localizeMethod == null || _localizationInstance == null) { return text; } try { return (string)_localizeMethod.Invoke(_localizationInstance, new object[1] { text }); } catch { return text; } } private static bool Matches(ItemData item, string itemPrefabName, string sharedName) { if (item?.m_shared == null) { return false; } if ((Object)(object)item.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == itemPrefabName) { return true; } if (sharedName != null) { return item.m_shared.m_name == sharedName; } return false; } internal static int CountItem(Inventory inv, string itemPrefabName) { if (inv == null) { return 0; } string sharedName = GetSharedName(itemPrefabName); int num = 0; foreach (ItemData allItem in inv.GetAllItems()) { if (Matches(allItem, itemPrefabName, sharedName)) { num += allItem.m_stack; } } return num; } private static void RemoveItem(Inventory inv, string itemPrefabName, int amount) { string sharedName = GetSharedName(itemPrefabName); int num = amount; foreach (ItemData item in new List<ItemData>(inv.GetAllItems())) { if (num <= 0) { break; } if (Matches(item, itemPrefabName, sharedName)) { int num2 = Mathf.Min(item.m_stack, num); inv.RemoveItem(item, num2); num -= num2; } } } } }