using Rebirth.RemoteCrafting; using System.Collections.Generic; namespace Features.RemoteCrafting { /// /// Patches to support the Crafting From Remote Storage /// public class EnhancedRecipeLists { /// /// Used to determine which recipes the player can craft based on the availability of ingredients in local containers. /// [HarmonyPatch(typeof(XUiC_RecipeList))] [HarmonyPatch("BuildRecipeInfosList")] public class BuildRecipeInfosList { public static bool Prefix(XUiC_RecipeList __instance, ref List _items) { var player = __instance.xui.playerUI.entityPlayer; _items.AddRange(RemoteCraftingUtils.SearchNearbyContainers(player)); return true; } } /// /// Extends what is considered to be in the player's backpack / tool belt to include local containers. /// [HarmonyPatch(typeof(XUiM_PlayerInventory))] [HarmonyPatch("GetAllItemStacks")] public class GetAllItemStacks { public static void Postfix(ref List __result, EntityPlayerLocal ___localPlayer) { __result.AddRange(RemoteCraftingUtils.SearchNearbyContainers(___localPlayer)); } } /// /// Hijacks the GetBindingValue so we can get an accurate count of all the items we have available, including from local storage. /// [HarmonyPatch(typeof(XUiC_IngredientEntry))] [HarmonyPatch("GetBindingValue")] public class GetBindingValue { public static bool Prefix(XUiC_IngredientEntry __instance, ref bool __result, ref string value, string bindingName, CachedStringFormatter ___needcountFormatter, CachedStringFormatter ___havecountFormatter, bool ___materialBased, ItemStack ___ingredient, string ___material, XUiC_RecipeCraftCount ___craftCountControl, CachedStringFormatterXuiRgbaColor ___itemicontintcolorFormatter) { var flag = ___ingredient != null; switch (bindingName) { case "haveneedcount": { var text = (flag ? ___needcountFormatter.Format(___ingredient.count * ___craftCountControl.Count) : ""); var value1 = 0; var childByType = __instance.WindowGroup.Controller.GetChildByType(); if (childByType != null) { if (___materialBased) { value = (flag ? (___havecountFormatter.Format(childByType.GetWeight(___material)) + "/" + text) : ""); } else { value = (flag ? (___havecountFormatter.Format( __instance.xui.PlayerInventory.GetItemCount(___ingredient.itemValue)) + "/" + text) : ""); } } else { var childByType2 = __instance.WindowGroup.Controller .GetChildByType(); if (childByType2 != null) { value = (flag ? (___havecountFormatter.Format( childByType2.GetItemCount(___ingredient.itemValue)) + "/" + text) : ""); } else { value = (flag ? (___havecountFormatter.Format( __instance.xui.PlayerInventory.GetItemCount(___ingredient.itemValue)) + "/" + text) : ""); if (flag) { // add items from lootcontainers value1 = __instance.xui.PlayerInventory.GetItemCount(___ingredient.itemValue); var array = RemoteCraftingUtils.SearchNearbyContainers(__instance.xui.playerUI.entityPlayer, ___ingredient.itemValue).ToArray(); foreach (var t in array) { if (t != null && t.itemValue.type != 0 && ___ingredient.itemValue.type == t.itemValue.type) { value1 += t.count; } } value = ___havecountFormatter.Format(value1) + "/" + text; } } } __result = true; return false; } default: return true; } } } /// /// Expands the HasItems search to include local containers. /// [HarmonyPatch(typeof(XUiM_PlayerInventory))] [HarmonyPatch("HasItems")] public class HasItems { public static bool Postfix(bool __result, IList _itemStacks, EntityPlayerLocal ___localPlayer, int _multiplier) { if (__result) return true; // We need to make sure we satisfy all of the items. var itemsWeHave = 0; foreach (var itemStack in _itemStacks) { var totalCount = 0; // This is how many we need. var num = itemStack.count * _multiplier; // check player inventory var slots = ___localPlayer.bag.GetSlots(); foreach (var entry in slots) { if (entry.IsEmpty()) continue; if (itemStack.itemValue.GetItemOrBlockId() != entry.itemValue.GetItemOrBlockId()) continue; totalCount += entry.count; // We have enough. if (totalCount >= num) { break; } } // We have enough. if (totalCount >= num) { itemsWeHave++; continue; } // Check the toolbelt now. slots = ___localPlayer.inventory.GetSlots(); foreach (var entry in slots) { if (entry.IsEmpty()) continue; if (itemStack.itemValue.GetItemOrBlockId() != entry.itemValue.GetItemOrBlockId()) continue; totalCount += entry.count; // We have enough. if (totalCount >= num) break; } // We have enough. if (totalCount >= num) { itemsWeHave++; continue; } // check container var containers = RemoteCraftingUtils.SearchNearbyContainers(___localPlayer, itemStack.itemValue); foreach (var stack in containers) { if (stack.IsEmpty()) continue; if (itemStack.itemValue.GetItemOrBlockId() != stack.itemValue.GetItemOrBlockId()) continue; totalCount += stack.count; // We have enough. if (totalCount >= num) break; } // We don't have enough for this. if (totalCount < num) { return false; } if (totalCount >= num) { itemsWeHave++; } } return itemsWeHave >= _itemStacks.Count; } } /// /// Removes from local storage containers items which we've consumed. /// [HarmonyPatch(typeof(XUiM_PlayerInventory))] [HarmonyPatch("RemoveItems")] public class RemoveItems { public static bool Prefix(XUiM_PlayerInventory __instance, IList _itemStacks, EntityPlayerLocal ___localPlayer, int _multiplier, IList _removedItems , Bag ___backpack, Inventory ___toolbelt) { RemoteCraftingUtils.ConsumeItem(_itemStacks, ___localPlayer, _multiplier, _removedItems, ___backpack, ___toolbelt); return false; } } // Code from OCB7D2D/OcbPinRecipes // Patch world unload to cleanup and save on exit [HarmonyPatch(typeof(World))] [HarmonyPatch("UnloadWorld")] public class WorldUnloadWorld { static void Postfix() { if (!Broadcastmanager.HasInstance) return; Broadcastmanager.Cleanup(); } } } }