From 751602a5e7ef3e8a6f9e4d6f5246c7d36499a141 Mon Sep 17 00:00:00 2001 From: yangzhi <@4F!xZpJwly&KbWq> Date: Wed, 12 Feb 2020 23:56:04 +0800 Subject: [PATCH] 1.Fix for Ldtoken IL 2.Fix shop menu list logic for Json Assets 3.Some method rewrite for compatibility --- .../Framework/ModLoading/RewriteHelper.cs | 6 +- .../CraftingPageMobileMethods.cs | 18 ++++ .../DiscreteColorPickerMethods.cs | 17 ++++ .../RewriteFacades/GameMenuMethods.cs | 12 +++ .../RewriteFacades/InventoryMenuMethods.cs | 22 +++++ .../RewriteFacades/ItemGrabMenuMethods.cs | 91 ++++++++++++++++++- .../MenuWithInventoryMethods.cs | 9 ++ .../Framework/RewriteFacades/NPCMethods.cs | 4 + src/SMAPI/Framework/SGame.cs | 20 ++-- src/SMAPI/Metadata/InstructionMetadata.cs | 6 ++ src/SMAPI/SMAPI.csproj | 3 + 11 files changed, 190 insertions(+), 18 deletions(-) create mode 100644 src/SMAPI/Framework/RewriteFacades/CraftingPageMobileMethods.cs create mode 100644 src/SMAPI/Framework/RewriteFacades/DiscreteColorPickerMethods.cs create mode 100644 src/SMAPI/Framework/RewriteFacades/InventoryMenuMethods.cs diff --git a/src/SMAPI/Framework/ModLoading/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/RewriteHelper.cs index f00e6cbe..795d0d2c 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteHelper.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteHelper.cs @@ -23,7 +23,7 @@ namespace StardewModdingAPI.Framework.ModLoading /// The IL instruction. public static FieldReference AsFieldReference(Instruction instruction) { - return instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld + return instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld || (instruction.OpCode == OpCodes.Ldtoken && instruction.Operand is FieldReference) ? (FieldReference)instruction.Operand : null; } @@ -32,14 +32,14 @@ namespace StardewModdingAPI.Framework.ModLoading /// The IL instruction. public static TypeReference AsTypeReference(Instruction instruction) { - return instruction.OpCode == OpCodes.Isinst ? (TypeReference)instruction.Operand : null; + return instruction.OpCode == OpCodes.Isinst || (instruction.OpCode == OpCodes.Ldtoken && instruction.Operand is TypeReference) ? (TypeReference)instruction.Operand : null; } /// Get the method reference from an instruction if it matches. /// The IL instruction. public static MethodReference AsMethodReference(Instruction instruction) { - return instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj + return instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj || (instruction.OpCode == OpCodes.Ldtoken && instruction.Operand is MethodReference) ? (MethodReference)instruction.Operand : null; } diff --git a/src/SMAPI/Framework/RewriteFacades/CraftingPageMobileMethods.cs b/src/SMAPI/Framework/RewriteFacades/CraftingPageMobileMethods.cs new file mode 100644 index 00000000..02c1372c --- /dev/null +++ b/src/SMAPI/Framework/RewriteFacades/CraftingPageMobileMethods.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using StardewValley; +using StardewValley.Menus; +using StardewValley.Objects; + +namespace StardewModdingAPI.Framework.RewriteFacades +{ + public class CraftingPageMobileMethods : CraftingPageMobile + { + public CraftingPageMobileMethods(int x, int y, int width, int height, bool cooking = false, bool standalone_menu = false, List material_containers = null) + : base(x, y, width, height, cooking, 300, material_containers) + { + } + } +} diff --git a/src/SMAPI/Framework/RewriteFacades/DiscreteColorPickerMethods.cs b/src/SMAPI/Framework/RewriteFacades/DiscreteColorPickerMethods.cs new file mode 100644 index 00000000..e7633fab --- /dev/null +++ b/src/SMAPI/Framework/RewriteFacades/DiscreteColorPickerMethods.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using StardewValley; +using StardewValley.Menus; + +namespace StardewModdingAPI.Framework.RewriteFacades +{ + public class DiscreteColorPickerMethods : DiscreteColorPicker + { + public DiscreteColorPickerMethods(int xPosition, int yPosition, int startingColor = 0, Item itemToDrawColored = null) + :base(xPosition, yPosition, startingColor, itemToDrawColored) + { + } + } +} diff --git a/src/SMAPI/Framework/RewriteFacades/GameMenuMethods.cs b/src/SMAPI/Framework/RewriteFacades/GameMenuMethods.cs index 184870f4..7d2270f7 100644 --- a/src/SMAPI/Framework/RewriteFacades/GameMenuMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/GameMenuMethods.cs @@ -16,5 +16,17 @@ namespace StardewModdingAPI.Framework.RewriteFacades typeof(GameMenu).GetField("hoverText", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).SetValue(this, value); } } + + public GameMenuMethods(bool playOpeningSound = true) : base() + { + } + + public GameMenuMethods(int startingTab, int extra = -1, bool playOpeningSound = true) : base(startingTab, extra) + { + } + public void changeTab(int whichTab, bool playSound = true) + { + base.changeTab(whichTab); + } } } diff --git a/src/SMAPI/Framework/RewriteFacades/InventoryMenuMethods.cs b/src/SMAPI/Framework/RewriteFacades/InventoryMenuMethods.cs new file mode 100644 index 00000000..f9bb75e7 --- /dev/null +++ b/src/SMAPI/Framework/RewriteFacades/InventoryMenuMethods.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using StardewValley; +using StardewValley.Menus; + +namespace StardewModdingAPI.Framework.RewriteFacades +{ + public class InventoryMenuMethods : InventoryMenu + { + public InventoryMenuMethods(int xPosition, int yPosition, bool playerInventory, IList actualInventory = null, highlightThisItem highlightMethod = null, + int capacity = -1, int rows = 3, int horizontalGap = 0, int verticalGap = 0, bool drawSlots = true) + : base(xPosition, yPosition, playerInventory, actualInventory, highlightMethod, capacity, rows, horizontalGap, verticalGap, drawSlots) + { + } + public Item rightClick(int x, int y, Item toAddTo, bool playSound = true, bool onlyCheckToolAttachments = false) + { + return base.rightClick(x, y, toAddTo, playSound); + } + } +} diff --git a/src/SMAPI/Framework/RewriteFacades/ItemGrabMenuMethods.cs b/src/SMAPI/Framework/RewriteFacades/ItemGrabMenuMethods.cs index 240a76e5..d4f38f42 100644 --- a/src/SMAPI/Framework/RewriteFacades/ItemGrabMenuMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/ItemGrabMenuMethods.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.Xna.Framework; using StardewValley; using StardewValley.Menus; @@ -6,12 +7,100 @@ namespace StardewModdingAPI.Framework.RewriteFacades { public class ItemGrabMenuMethods : ItemGrabMenu { + public ClickableTextureComponent FillStacksButtonProp + { + get + { + ClickableTextureComponent textureComponent1 = new ClickableTextureComponent("", new Rectangle(this.xPositionOnScreen + this.width, this.yPositionOnScreen + this.height / 3 - 64 - 64 - 16, 64, 64), "", Game1.content.LoadString("Strings\\UI:ItemGrab_FillStacks"), Game1.mouseCursors, new Rectangle(103, 469, 16, 16), 4f, false); + textureComponent1.myID = 12952; + textureComponent1.upNeighborID = this.colorPickerToggleButton != null ? 27346 : (this.specialButton != null ? 12485 : -500); + textureComponent1.downNeighborID = 106; + textureComponent1.leftNeighborID = 53921; + textureComponent1.region = 15923; + return textureComponent1; + } + set + { + } + } + public ItemGrabMenuMethods(IList inventory, bool reverseGrab, bool showReceivingMenu, InventoryMenu.highlightThisItem highlightFunction, ItemGrabMenu.behaviorOnItemSelect behaviorOnItemSelectFunction, string message, ItemGrabMenu.behaviorOnItemSelect behaviorOnItemGrab = null, bool snapToBottom = false, bool canBeExitedWithKey = false, bool playRightClickSound = true, bool allowRightClick = true, bool showOrganizeButton = false, int source = 0, Item sourceItem = null, int whichSpecialButton = -1, object context = null) : base(inventory, reverseGrab, showReceivingMenu, highlightFunction, behaviorOnItemSelectFunction, message, behaviorOnItemGrab, snapToBottom, canBeExitedWithKey, playRightClickSound, allowRightClick, showOrganizeButton, source, sourceItem, whichSpecialButton, context, -1, 3, null, true, null, false, null) { } public ItemGrabMenuMethods(IList inventory, object context = null) : base(inventory) { } - + + public void FillOutStacks() + { + for (int index1 = 0; index1 < this.ItemsToGrabMenu.actualInventory.Count; ++index1) + { + Item obj1 = this.ItemsToGrabMenu.actualInventory[index1]; + if (obj1 != null && obj1.maximumStackSize() > 1) + { + for (int index2 = 0; index2 < this.inventory.actualInventory.Count; ++index2) + { + Item stack1 = this.inventory.actualInventory[index2]; + if (stack1 != null && obj1.canStackWith((ISalable)stack1)) + { + //this._transferredItemSprites.Add(new ItemGrabMenu.TransferredItemSprite(stack1.getOne(), this.inventory.inventory[index2].bounds.X, this.inventory.inventory[index2].bounds.Y)); + int stack2 = stack1.Stack; + if (obj1.getRemainingStackSpace() > 0) + { + stack2 = obj1.addToStack(stack1); + //this.ItemsToGrabMenu.ShakeItem(obj1); + } + int stack3; + for (stack1.Stack = stack2; stack1.Stack > 0; stack1.Stack = stack3) + { + Item obj2 = (Item)null; + if (Utility.canItemBeAddedToThisInventoryList(obj1.getOne(), this.ItemsToGrabMenu.actualInventory, this.ItemsToGrabMenu.capacity)) + { + if (obj2 == null) + { + for (int index3 = 0; index3 < this.ItemsToGrabMenu.actualInventory.Count; ++index3) + { + if (this.ItemsToGrabMenu.actualInventory[index3] != null && this.ItemsToGrabMenu.actualInventory[index3].canStackWith((ISalable)obj1) && this.ItemsToGrabMenu.actualInventory[index3].getRemainingStackSpace() > 0) + { + obj2 = this.ItemsToGrabMenu.actualInventory[index3]; + break; + } + } + } + if (obj2 == null) + { + for (int index3 = 0; index3 < this.ItemsToGrabMenu.actualInventory.Count; ++index3) + { + if (this.ItemsToGrabMenu.actualInventory[index3] == null) + { + obj2 = this.ItemsToGrabMenu.actualInventory[index3] = obj1.getOne(); + obj2.Stack = 0; + break; + } + } + } + if (obj2 == null && this.ItemsToGrabMenu.actualInventory.Count < this.ItemsToGrabMenu.capacity) + { + obj2 = obj1.getOne(); + this.ItemsToGrabMenu.actualInventory.Add(obj2); + } + if (obj2 != null) + { + stack3 = obj2.addToStack(stack1); + //this.ItemsToGrabMenu.ShakeItem(obj2); + } + else + break; + } + else + break; + } + if (stack1.Stack == 0) + this.inventory.actualInventory[index2] = (Item)null; + } + } + } + } + } } } diff --git a/src/SMAPI/Framework/RewriteFacades/MenuWithInventoryMethods.cs b/src/SMAPI/Framework/RewriteFacades/MenuWithInventoryMethods.cs index 26af2341..32934ec8 100644 --- a/src/SMAPI/Framework/RewriteFacades/MenuWithInventoryMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/MenuWithInventoryMethods.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; using StardewValley; using StardewValley.Menus; @@ -23,5 +24,13 @@ namespace StardewModdingAPI.Framework.RewriteFacades { } } + public MenuWithInventoryMethods(InventoryMenu.highlightThisItem highlighterMethod = null, bool okButton = false, bool trashCan = false, int inventoryXOffset = 0, int inventoryYOffset = 0, int menuOffsetHack = 0) : base(highlighterMethod, okButton, trashCan, inventoryXOffset, inventoryYOffset) + { + } + public virtual void draw(SpriteBatch b, bool drawUpperPortion = true, bool drawDescriptionArea = true, int red = -1, int green = -1, int blue = -1) + { + base.draw(b); + base.draw(b, red, green, blue); + } } } diff --git a/src/SMAPI/Framework/RewriteFacades/NPCMethods.cs b/src/SMAPI/Framework/RewriteFacades/NPCMethods.cs index 1c7c2001..91c2a515 100644 --- a/src/SMAPI/Framework/RewriteFacades/NPCMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/NPCMethods.cs @@ -8,6 +8,10 @@ namespace StardewModdingAPI.Framework.RewriteFacades { public class NPCMethods : NPC { + public void reloadSprite() + { + base.reloadSprite(Game1.emergencyLoading); + } public void checkSchedule(int timeOfDay) { base.checkSchedule(timeOfDay, Game1.emergencyLoading); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index c2530435..265e4348 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -699,15 +699,6 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Context: menu changed from {state.ActiveMenu.Old?.GetType().FullName ?? "none"} to {state.ActiveMenu.New?.GetType().FullName ?? "none"}.", LogLevel.Trace); // raise menu events - int forSaleCount = 0; - Dictionary itemPriceAndStock; - List forSale; - if (now is ShopMenu shop && !(was is ShopMenu)) - { - itemPriceAndStock = this.Reflection.GetField>(shop, "itemPriceAndStock").GetValue(); - forSale = this.Reflection.GetField>(shop, "forSale").GetValue(); - forSaleCount = forSale.Count; - } events.MenuChanged.Raise(new MenuChangedEventArgs(was, now)); if (now is GameMenu gameMenu) @@ -723,15 +714,16 @@ namespace StardewModdingAPI.Framework } } } - else if (now is ShopMenu shopMenu && !(was is ShopMenu)) + else if (now is ShopMenu shopMenu) { - itemPriceAndStock = this.Reflection.GetField>(shopMenu, "itemPriceAndStock").GetValue(); - forSale = this.Reflection.GetField>(shopMenu, "forSale").GetValue(); - if (forSaleCount != forSale.Count) + Dictionary itemPriceAndStock = this.Reflection.GetField>(shopMenu, "itemPriceAndStock").GetValue(); + if (shopMenu.forSaleButtons.Count < itemPriceAndStock.Keys.Select(item => item.Name).Distinct().Count()) { + this.Monitor.Log($"Shop Menu Pop"); Game1.activeClickableMenu = new ShopMenu(itemPriceAndStock, this.Reflection.GetField(shopMenu, "currency").GetValue(), - this.Reflection.GetField(shopMenu, "personName").GetValue()); + this.Reflection.GetField(shopMenu, "personName").GetValue(), + shopMenu.onPurchase, shopMenu.onSell, shopMenu.storeContext); } } } diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index b07c4597..e22d8317 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -61,6 +61,7 @@ namespace StardewModdingAPI.Metadata yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(ShopMenu), typeof(ShopMenuMethods), "hoverText", "HoverTextProp"); yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(ShopMenu), typeof(ShopMenuMethods), "categoriesToSellHere", "CategoriesToSellHereProp"); yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods), "trashCan", "TrashCanProp"); + yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods), "fillStacksButton", "FillStacksButtonProp"); // Rewrite Missing Type yield return new TypeReferenceRewriter("StardewValley.Menus.CraftingPage", typeof(CraftingPageMobile)); @@ -81,6 +82,11 @@ namespace StardewModdingAPI.Metadata yield return new MethodParentRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods)); yield return new MethodParentRewriter(typeof(WeatherDebris), typeof(WeatherDebrisMethods)); yield return new MethodParentRewriter(typeof(Debris), typeof(DebrisMethods)); + yield return new MethodParentRewriter(typeof(DiscreteColorPicker), typeof(DiscreteColorPickerMethods)); + yield return new MethodParentRewriter(typeof(InventoryMenu), typeof(InventoryMenuMethods)); + yield return new MethodParentRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods)); + yield return new MethodParentRewriter(typeof(GameMenu), typeof(GameMenuMethods)); + yield return new MethodParentRewriter(typeof(CraftingPageMobile), typeof(CraftingPageMobileMethods)); //Field Rewriters yield return new FieldReplaceRewriter(typeof(ItemGrabMenu), "context", "specialObject"); diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 383a9aa4..daca0d18 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -256,6 +256,9 @@ + + +