1.Fix for Ldtoken IL

2.Fix shop menu list logic for Json Assets
3.Some method rewrite for compatibility
This commit is contained in:
yangzhi 2020-02-12 23:56:04 +08:00 committed by Chris
parent c44bda0991
commit 751602a5e7
11 changed files with 190 additions and 18 deletions

View File

@ -23,7 +23,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <param name="instruction">The IL instruction.</param> /// <param name="instruction">The IL instruction.</param>
public static FieldReference AsFieldReference(Instruction 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 ? (FieldReference)instruction.Operand
: null; : null;
} }
@ -32,14 +32,14 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <param name="instruction">The IL instruction.</param> /// <param name="instruction">The IL instruction.</param>
public static TypeReference AsTypeReference(Instruction 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;
} }
/// <summary>Get the method reference from an instruction if it matches.</summary> /// <summary>Get the method reference from an instruction if it matches.</summary>
/// <param name="instruction">The IL instruction.</param> /// <param name="instruction">The IL instruction.</param>
public static MethodReference AsMethodReference(Instruction 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 ? (MethodReference)instruction.Operand
: null; : null;
} }

View File

@ -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<Chest> material_containers = null)
: base(x, y, width, height, cooking, 300, material_containers)
{
}
}
}

View File

@ -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)
{
}
}
}

View File

@ -16,5 +16,17 @@ namespace StardewModdingAPI.Framework.RewriteFacades
typeof(GameMenu).GetField("hoverText", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).SetValue(this, value); 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);
}
} }
} }

View File

@ -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<Item> 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);
}
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Xna.Framework;
using StardewValley; using StardewValley;
using StardewValley.Menus; using StardewValley.Menus;
@ -6,12 +7,100 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{ {
public class ItemGrabMenuMethods : ItemGrabMenu 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<Item> 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) public ItemGrabMenuMethods(IList<Item> 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) : 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<Item> inventory, object context = null) public ItemGrabMenuMethods(IList<Item> inventory, object context = null)
: base(inventory) { } : 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;
}
}
}
}
}
} }
} }

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewValley; using StardewValley;
using StardewValley.Menus; 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);
}
} }
} }

View File

@ -8,6 +8,10 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{ {
public class NPCMethods : NPC public class NPCMethods : NPC
{ {
public void reloadSprite()
{
base.reloadSprite(Game1.emergencyLoading);
}
public void checkSchedule(int timeOfDay) public void checkSchedule(int timeOfDay)
{ {
base.checkSchedule(timeOfDay, Game1.emergencyLoading); base.checkSchedule(timeOfDay, Game1.emergencyLoading);

View File

@ -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); 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 // raise menu events
int forSaleCount = 0;
Dictionary<ISalable, int[]> itemPriceAndStock;
List<Item> forSale;
if (now is ShopMenu shop && !(was is ShopMenu))
{
itemPriceAndStock = this.Reflection.GetField<Dictionary<ISalable, int[]>>(shop, "itemPriceAndStock").GetValue();
forSale = this.Reflection.GetField<List<Item>>(shop, "forSale").GetValue();
forSaleCount = forSale.Count;
}
events.MenuChanged.Raise(new MenuChangedEventArgs(was, now)); events.MenuChanged.Raise(new MenuChangedEventArgs(was, now));
if (now is GameMenu gameMenu) 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<Dictionary<ISalable, int[]>>(shopMenu, "itemPriceAndStock").GetValue(); Dictionary<ISalable, int[]> itemPriceAndStock = this.Reflection.GetField<Dictionary<ISalable, int[]>>(shopMenu, "itemPriceAndStock").GetValue();
forSale = this.Reflection.GetField<List<Item>>(shopMenu, "forSale").GetValue(); if (shopMenu.forSaleButtons.Count < itemPriceAndStock.Keys.Select(item => item.Name).Distinct().Count())
if (forSaleCount != forSale.Count)
{ {
this.Monitor.Log($"Shop Menu Pop");
Game1.activeClickableMenu = new ShopMenu(itemPriceAndStock, Game1.activeClickableMenu = new ShopMenu(itemPriceAndStock,
this.Reflection.GetField<int>(shopMenu, "currency").GetValue(), this.Reflection.GetField<int>(shopMenu, "currency").GetValue(),
this.Reflection.GetField<string>(shopMenu, "personName").GetValue()); this.Reflection.GetField<string>(shopMenu, "personName").GetValue(),
shopMenu.onPurchase, shopMenu.onSell, shopMenu.storeContext);
} }
} }
} }

View File

@ -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), "hoverText", "HoverTextProp");
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(ShopMenu), typeof(ShopMenuMethods), "categoriesToSellHere", "CategoriesToSellHereProp"); 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(MenuWithInventory), typeof(MenuWithInventoryMethods), "trashCan", "TrashCanProp");
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods), "fillStacksButton", "FillStacksButtonProp");
// Rewrite Missing Type // Rewrite Missing Type
yield return new TypeReferenceRewriter("StardewValley.Menus.CraftingPage", typeof(CraftingPageMobile)); 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(ItemGrabMenu), typeof(ItemGrabMenuMethods));
yield return new MethodParentRewriter(typeof(WeatherDebris), typeof(WeatherDebrisMethods)); yield return new MethodParentRewriter(typeof(WeatherDebris), typeof(WeatherDebrisMethods));
yield return new MethodParentRewriter(typeof(Debris), typeof(DebrisMethods)); 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 //Field Rewriters
yield return new FieldReplaceRewriter(typeof(ItemGrabMenu), "context", "specialObject"); yield return new FieldReplaceRewriter(typeof(ItemGrabMenu), "context", "specialObject");

View File

@ -256,6 +256,9 @@
<Compile Include="Framework\RequestExitDelegate.cs" /> <Compile Include="Framework\RequestExitDelegate.cs" />
<Compile Include="Framework\RewriteFacades\DebrisMethods.cs" /> <Compile Include="Framework\RewriteFacades\DebrisMethods.cs" />
<Compile Include="Framework\RewriteFacades\GameMenuMethods.cs" /> <Compile Include="Framework\RewriteFacades\GameMenuMethods.cs" />
<Compile Include="Framework\RewriteFacades\InventoryMenuMethods.cs" />
<Compile Include="Framework\RewriteFacades\DiscreteColorPickerMethods.cs" />
<Compile Include="Framework\RewriteFacades\CraftingPageMobileMethods.cs" />
<Compile Include="Framework\RewriteFacades\ShopMenuMethods.cs" /> <Compile Include="Framework\RewriteFacades\ShopMenuMethods.cs" />
<Compile Include="Framework\RewriteFacades\FarmerMethods.cs" /> <Compile Include="Framework\RewriteFacades\FarmerMethods.cs" />
<Compile Include="Framework\RewriteFacades\FarmerRenderMethods.cs" /> <Compile Include="Framework\RewriteFacades\FarmerRenderMethods.cs" />