Rewrites, added harmony patch, VK fix

This commit is contained in:
Chris 2019-07-02 18:57:53 -04:00
parent dbf53dc3eb
commit 8fc324a86a
24 changed files with 401 additions and 150 deletions

View File

@ -71,10 +71,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
..\.github\ISSUE_TEMPLATE\general.md = ..\.github\ISSUE_TEMPLATE\general.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI", "StardewModdingAPI\StardewModdingAPI.csproj", "{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI.Mods.VirtualKeyboard", "StardewModdingAPI.Mods.VirtualKeyboard\StardewModdingAPI.Mods.VirtualKeyboard.csproj", "{29CCE9C9-6811-415D-A681-A6D47073924D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI", "SMAPI\StardewModdingAPI.csproj", "{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
SMAPI.Internal\SMAPI.Internal.projitems*{443ddf81-6aaf-420a-a610-3459f37e5575}*SharedItemsImports = 4
@ -127,14 +127,14 @@ Global
{D5CFD923-37F1-4BC3-9BE8-E506E202AC28}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5CFD923-37F1-4BC3-9BE8-E506E202AC28}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5CFD923-37F1-4BC3-9BE8-E506E202AC28}.Release|Any CPU.Build.0 = Release|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Release|Any CPU.Build.0 = Release|Any CPU
{29CCE9C9-6811-415D-A681-A6D47073924D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29CCE9C9-6811-415D-A681-A6D47073924D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29CCE9C9-6811-415D-A681-A6D47073924D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29CCE9C9-6811-415D-A681-A6D47073924D}.Release|Any CPU.Build.0 = Release|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -22,6 +22,9 @@ namespace StardewModdingAPI
/// <summary>SMAPI's current semantic version.</summary>
public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.11.2");
/// <summary>Android SMAPI's current semantic version.</summary>
public static ISemanticVersion AndroidApiVersion { get; } = new Toolkit.SemanticVersion("0.8.7");
/// <summary>The minimum supported version of Stardew Valley.</summary>
public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.36");

View File

@ -26,6 +26,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
private readonly IMonitor Monitor;
private readonly bool UsingInstance;
private readonly bool RainDropFix;
/*********
** Public methods
*********/
@ -33,7 +37,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <param name="type">The type whose field to which references should be rewritten.</param>
/// <param name="fieldName">The field name to rewrite.</param>
/// <param name="propertyName">The property name (if different).</param>
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, string propertyName, IMonitor monitor, string testName = null)
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, string propertyName, IMonitor monitor, string testName = null, bool usingInstance = true, bool rainDropFix = false)
: base(type.FullName, fieldName, InstructionHandleResult.None)
{
this.Monitor = monitor;
@ -42,13 +46,15 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
this.FieldName = fieldName;
this.PropertyName = propertyName;
this.TestName = testName;
this.UsingInstance = usingInstance;
this.RainDropFix = rainDropFix;
}
/// <summary>Construct an instance.</summary>
/// <param name="type">The type whose field to which references should be rewritten.</param>
/// <param name="fieldName">The field name to rewrite.</param>
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, IMonitor monitor)
: this(type, toType, fieldName, fieldName, monitor) { }
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, IMonitor monitor, string testName = null, bool usingInstance = true, bool rainDropFix = false)
: this(type, toType, fieldName, fieldName, monitor, testName, usingInstance, rainDropFix) { }
/// <summary>Perform the predefined logic for an instruction if applicable.</summary>
/// <param name="module">The assembly module containing the instruction.</param>
@ -61,8 +67,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
if (!this.IsMatch(instruction))
return InstructionHandleResult.None;
//string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get";
try
{
if (this.TestName == null && !this.RainDropFix)
{
MethodReference method = module.ImportReference(this.ToType.GetMethod($"get_{this.PropertyName}"));
FieldReference field = module.ImportReference(this.ToType.GetField(this.FieldName));
@ -70,6 +77,30 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
cil.InsertAfter(instruction, cil.Create(OpCodes.Ldfld, field));
cil.Replace(instruction, cil.Create(OpCodes.Call, method));
}
else if (this.TestName != null && this.UsingInstance && !this.RainDropFix)
{
MethodReference method = module.ImportReference(this.ToType.GetMethod($"get_{this.PropertyName}"));
MethodReference field = module.ImportReference(this.ToType.GetMethod($"get_{this.TestName}"));
cil.InsertAfter(instruction, cil.Create(OpCodes.Callvirt, field));
cil.Replace(instruction, cil.Create(OpCodes.Call, method));
}
else if (this.RainDropFix && !this.UsingInstance)
{
FieldReference field = module.ImportReference(this.ToType.GetField(this.FieldName));
cil.Replace(instruction, cil.Create(OpCodes.Ldsfld, field));
}
else
{
MethodReference method = module.ImportReference(this.Type.GetMethod($"get_{this.FieldName}"));
MethodReference field = module.ImportReference(this.ToType.GetMethod($"get_{this.TestName}"));
cil.InsertAfter(instruction, cil.Create(OpCodes.Callvirt, field));
cil.Replace(instruction, cil.Create(OpCodes.Call, method));
}
}
catch (Exception e)
{
this.Monitor.Log(e.Message);

View File

@ -29,7 +29,7 @@ namespace StardewModdingAPI.Framework.Patching
/// <param name="patches">The patches to apply.</param>
public void Apply(params IHarmonyPatch[] patches)
{
if(Build.VERSION.SdkInt > BuildVersionCodes.LollipopMr1)
if (Build.VERSION.SdkInt > BuildVersionCodes.LollipopMr1)
{
HarmonyDetourBridge.Init();
@ -47,6 +47,10 @@ namespace StardewModdingAPI.Framework.Patching
}
}
}
else
{
this.Monitor.Log("Harmony mods are not supported on this Android Version.");
}
}
}
}

View File

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using StardewValley;
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class DebrisMethods : Debris
{
public DebrisMethods(Item item, Vector2 debrisOrigin)
: base()
{
base.init(item, debrisOrigin);
}
public DebrisMethods(int objectIndex, Vector2 debrisOrigin, Vector2 playerPosition)
: base()
{
base.init(objectIndex, debrisOrigin, playerPosition);
}
public DebrisMethods(Item item, Vector2 debrisOrigin, Vector2 targetLocation)
: base()
{
base.init(item, debrisOrigin, targetLocation);
}
public DebrisMethods(string spriteSheet, int numberOfChunks, Vector2 debrisOrigin)
: base()
{
base.init(spriteSheet, numberOfChunks, debrisOrigin);
}
public DebrisMethods(string spriteSheet, Rectangle sourceRect, int numberOfChunks, Vector2 debrisOrigin)
: base()
{
base.init(spriteSheet, sourceRect, numberOfChunks, debrisOrigin);
}
public DebrisMethods(int debrisType, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition)
: base()
{
base.init(debrisType, numberOfChunks, debrisOrigin, playerPosition);
}
public DebrisMethods(int number, Vector2 debrisOrigin, Color messageColor, float scale, Character toHover)
: base()
{
base.init(number, debrisOrigin, messageColor, scale, toHover);
}
public DebrisMethods(int debrisType, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, float velocityMultiplayer)
: base()
{
base.init(debrisType, numberOfChunks, debrisOrigin, playerPosition, velocityMultiplayer);
}
public DebrisMethods(string message, int numberOfChunks, Vector2 debrisOrigin, Color messageColor, float scale, float rotation)
: base()
{
base.init(message, numberOfChunks, debrisOrigin, messageColor, scale, rotation);
}
public DebrisMethods(string spriteSheet, Rectangle sourceRect, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, int groundLevel)
: base()
{
base.init(spriteSheet, sourceRect, numberOfChunks, debrisOrigin, playerPosition, groundLevel);
}
public DebrisMethods(int type, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, int groundLevel, int color = -1)
: base()
{
base.init(type, numberOfChunks, debrisOrigin, playerPosition, groundLevel, color);
}
public DebrisMethods(string spriteSheet, Rectangle sourceRect, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, int groundLevel, int sizeOfSourceRectSquares)
: base()
{
base.init(spriteSheet, sourceRect, numberOfChunks, debrisOrigin, playerPosition, groundLevel, sizeOfSourceRectSquares);
}
}
}

View File

@ -4,7 +4,7 @@ using StardewValley;
namespace StardewModdingAPI.Framework.RewriteFacades
{
class FarmerMethods : Farmer
public class FarmerMethods : Farmer
{
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new bool couldInventoryAcceptThisItem(Item item)
@ -13,10 +13,10 @@ namespace StardewModdingAPI.Framework.RewriteFacades
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
//public new bool addItemToInventoryBool(Item item)
//{
// return base.addItemToInventoryBool(item, false);
//}
public new bool addItemToInventoryBool(Item item)
{
return base.addItemToInventoryBool(item, false);
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new int freeSpotsInInventory()

View File

@ -10,7 +10,7 @@ namespace StardewModdingAPI.Framework.RewriteFacades
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new void drawMiniPortrat(SpriteBatch b, Vector2 position, float layerDepth, float scale, int facingDirection, Farmer who)
{
base.drawMiniPortrat(b, position, layerDepth, scale, facingDirection, who);
base.drawMiniPortrat(b, position, layerDepth, scale, facingDirection, who, false);
}
}
}

View File

@ -1,11 +1,22 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
using StardewValley.Menus;
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class Game1Methods : Game1
{
public RainDrop[] rainDrops = (typeof(RainManager).GetField("_rainDropList", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(RainManager.Instance) as List<RainDrop>).ToArray();
public new IList<IClickableMenu> onScreenMenus = Game1.onScreenMenus;
public static void updateDebrisWeatherForMovement(List<WeatherDebris> debris)
{
WeatherDebrisManager.Instance.UpdateDebrisWeatherForMovement();
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public static new string parseText(string text, SpriteFont whichFont, int width)
{
@ -17,6 +28,7 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{
warpFarmer(locationRequest, tileX, tileY, facingDirectionAfterWarp, true, false);
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public static new void warpFarmer(string locationName, int tileX, int tileY, bool flip)
{
@ -28,5 +40,10 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{
warpFarmer(locationName, tileX, tileY, facingDirectionAfterWarp, false, true, false);
}
public static void panScreen(int x, int y)
{
panScreen(x, y, 0);
}
}
}

View File

@ -2,16 +2,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Netcode;
using StardewValley;
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class GameLocationMethods : GameLocation
{
// public virtual void seasonUpdate(string season, bool onLoad = false)
// {
// base.seasonUpdate(season, onLoad, Game1.emergencyLoading);
// }
}
}

View File

@ -16,7 +16,12 @@ namespace StardewModdingAPI.Framework.RewriteFacades
public static void drawStringHorizontallyCenteredAt(SpriteBatch b, string s, int x, int y, int characterPosition = 999999, int width = -1, int height = 999999, float alpha = -1f, float layerDepth = 0.88f, bool junimoText = false, int color = -1, int maxWdith = 99999)
{
SpriteText.drawString(b, s, x - SpriteText.getWidthOfString(s) / 2, y, characterPosition, width, height, alpha, layerDepth, junimoText, -1, "", color);
drawString(b, s, x - SpriteText.getWidthOfString(s) / 2, y, characterPosition, width, height, alpha, layerDepth, junimoText, -1, "", color);
}
public static void drawStringWithScrollBackground(SpriteBatch b, string s, int x, int y, string placeHolderWidthText, float alpha, int color)
{
drawStringWithScrollBackground(b, s, x, y, placeHolderWidthText, alpha, color, 0.088f);
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using StardewValley;
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class WeatherDebrisMethods : WeatherDebris
{
public WeatherDebrisMethods(Vector2 position, int which, float rotationVelocity, float dx, float dy)
: base(position, which, dx, dy)
{
}
}
}

View File

@ -160,6 +160,7 @@ namespace StardewModdingAPI.Framework
// init logging
this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GameVersion} on {EnvironmentUtility.GetFriendlyPlatformName(Constants.Platform)}", LogLevel.Info);
this.Monitor.Log($"MartyrPher's Android SMAPI Loader: {Constants.AndroidApiVersion} on Android: {Android.OS.Build.VERSION.Sdk}", LogLevel.Info);
this.Monitor.Log($"Mods go here: {modsPath}");
if (modsPath != Constants.DefaultModsPath)
this.Monitor.Log("(Using custom --mods-path argument.)", LogLevel.Trace);
@ -235,7 +236,8 @@ namespace StardewModdingAPI.Framework
new GamePatcher(this.Monitor).Apply(
new DialogueErrorPatch(this.MonitorForGame, this.Reflection),
new ObjectErrorPatch(),
new LoadForNewGamePatch(this.Reflection, this.GameInstance.OnLoadStageChanged)
new LoadForNewGamePatch(this.Reflection, this.GameInstance.OnLoadStageChanged),
new SaveBackupPatch(this.EventManager)
);
// add exit handler
@ -259,7 +261,7 @@ namespace StardewModdingAPI.Framework
}).Start();
// set window titles
this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion}";
//this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion}";
//Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion}";
#if SMAPI_3_0_STRICT
this.GameInstance.Window.Title += " [SMAPI 3.0 strict mode]";
@ -307,24 +309,24 @@ namespace StardewModdingAPI.Framework
{
this.IsGameRunning = true;
StardewValley.Program.releaseBuild = true; // game's debug logic interferes with SMAPI opening the game window
//this.GameInstance.Run();
this.GameInstance.Run();
}
catch (InvalidOperationException ex) when (ex.Source == "Microsoft.Xna.Framework.Xact" && ex.StackTrace.Contains("Microsoft.Xna.Framework.Audio.AudioEngine..ctor"))
{
this.Monitor.Log("The game couldn't load audio. Do you have speakers or headphones plugged in?", LogLevel.Error);
this.Monitor.Log($"Technical details: {ex.GetLogSummary()}", LogLevel.Trace);
this.PressAnyKeyToExit();
//this.PressAnyKeyToExit();
}
catch (FileNotFoundException ex) when (ex.Message == "Could not find file 'C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Stardew Valley\\Content\\XACT\\FarmerSounds.xgs'.") // path in error is hardcoded regardless of install path
{
this.Monitor.Log("The game can't find its Content\\XACT\\FarmerSounds.xgs file. You can usually fix this by resetting your content files (see https://smapi.io/troubleshoot#reset-content ), or by uninstalling and reinstalling the game.", LogLevel.Error);
this.Monitor.Log($"Technical details: {ex.GetLogSummary()}", LogLevel.Trace);
this.PressAnyKeyToExit();
//this.PressAnyKeyToExit();
}
catch (Exception ex)
{
this.MonitorForGame.Log($"The game failed to launch: {ex.GetLogSummary()}", LogLevel.Error);
this.PressAnyKeyToExit();
//this.PressAnyKeyToExit();
}
finally
{

View File

@ -1078,7 +1078,7 @@ namespace StardewModdingAPI.Framework
[SuppressMessage("ReSharper", "RedundantTypeArgumentsOfMethod", Justification = "copied from game code as-is")]
[SuppressMessage("SMAPI.CommonErrors", "AvoidNetField", Justification = "copied from game code as-is")]
[SuppressMessage("SMAPI.CommonErrors", "AvoidImplicitNetFieldCast", Justification = "copied from game code as-is")]
private void DrawImpl(GameTime gameTime)
private void DrawImpl(GameTime gameTime, RenderTarget2D toBuffer = null)
{
var events = this.Events;
if (skipNextDrawCall)
@ -1118,11 +1118,21 @@ namespace StardewModdingAPI.Framework
if (_newDayTask != null)
{
base.GraphicsDevice.Clear(bgColor.GetValue());
if (Game1.showInterDayScroll)
{
Matrix value = Matrix.CreateScale(1f);
Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, new Matrix?(value));
SpriteText.drawStringWithScrollCenteredAt(Game1.spriteBatch, Game1.content.LoadString("Strings\\UI:please_wait"), base.GraphicsDevice.Viewport.Width / 2, base.GraphicsDevice.Viewport.Height / 2, "", 1f, -1, 0, 0.088f, false);
Game1.spriteBatch.End();
}
return;
}
if (options.zoomLevel != 1f)
{
base.GraphicsDevice.SetRenderTarget(screen);
if (toBuffer != null)
base.GraphicsDevice.SetRenderTarget(toBuffer);
else
base.GraphicsDevice.SetRenderTarget(this.screen);
}
if (IsSaving)
{

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.ModLoading;
@ -42,9 +43,13 @@ namespace StardewModdingAPI.Metadata
// rewrite for crossplatform compatibility
yield return new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchMethods), onlyIfPlatformChanged: true);
//isRaining and isDebrisWeather fix 50% done.
//isRaining and isDebrisWeather fix 75% done.
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(RainManager), "isRaining", "Instance", this.Monitor);
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(WeatherDebrisManager), "isDebrisWeather", "Instance", this.Monitor);
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(GameLocation), typeof(DebrisManager), "debris", "Instance", this.Monitor, "debrisNetCollection", false);
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(WeatherDebrisManager), "debrisWeather", "Instance", this.Monitor, "weatherDebrisList");
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(Game1Methods), "rainDrops", "Instance", this.Monitor, null, false, true);
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(Game1Methods), "onScreenMenus", "", this.Monitor, null, false, true);
//Method Rewrites
yield return new MethodParentRewriter(typeof(Game1), typeof(Game1Methods));
@ -53,19 +58,20 @@ namespace StardewModdingAPI.Metadata
yield return new MethodParentRewriter(typeof(FarmerRenderer), typeof(FarmerRendererMethods));
yield return new MethodParentRewriter(typeof(SpriteText), typeof(SpriteTextMethods));
yield return new MethodParentRewriter(typeof(NPC), typeof(NPCMethods));
yield return new MethodParentRewriter(typeof(GameLocation), typeof(GameLocationMethods));
//Constructor Rewrites
yield return new MethodParentRewriter(typeof(HUDMessage), typeof(HUDMessageMethods));
yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods));
yield return new MethodParentRewriter(typeof(TextBox), typeof(TextBoxMethods));
yield return new MethodParentRewriter(typeof(WeatherDebris), typeof(WeatherDebrisMethods));
yield return new MethodParentRewriter(typeof(Debris), typeof(DebrisMethods));
//Field Rewriters
yield return new FieldReplaceRewriter(typeof(ItemGrabMenu), "context", "specialObject");
yield return new FieldReplaceRewriter(typeof(FarmerTeam), "demolishLock", "buildingLock");
// rewrite for Stardew Valley 1.3
yield return new StaticFieldToConstantRewriter<int>(typeof(Game1), "tileSize", Game1.tileSize);
//yield return new TypeReferenceRewriter("System.Collections.Generic.IList`1<StardewValley.Menus.IClickableMenu>", typeof(List<IClickableMenu>));
yield return new FieldToPropertyRewriter(typeof(Game1), "player");
yield return new FieldToPropertyRewriter(typeof(Game1), "currentLocation");
yield return new FieldToPropertyRewriter(typeof(Character), "currentLocation");

View File

@ -0,0 +1,67 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Harmony;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events;
using StardewModdingAPI.Framework.Patching;
using StardewValley;
namespace StardewModdingAPI.Patches
{
internal class SaveBackupPatch : IHarmonyPatch
{
/*********
** Accessors
*********/
/// <summary>A unique name for this patch.</summary>
public string Name => $"{nameof(SaveBackupPatch)}";
/// <summary>An Instance of <see cref="EventManager"/>.</summary>
private static EventManager Events;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
/// <param name="eventManager">SMAPI's EventManager Instance</param>
public SaveBackupPatch(EventManager eventManager)
{
SaveBackupPatch.Events = eventManager;
}
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
public void Apply(HarmonyInstance harmony)
{
MethodInfo makeFullBackup = AccessTools.Method(typeof(Game1), nameof(Game1.MakeFullBackup));
MethodInfo saveWholeBackup = AccessTools.Method(typeof(Game1), nameof(Game1.saveWholeBackup));
MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(SaveBackupPatch.Prefix));
MethodInfo postfix = AccessTools.Method(this.GetType(), nameof(SaveBackupPatch.PostFix));
harmony.Patch(makeFullBackup, new HarmonyMethod(prefix), new HarmonyMethod(postfix));
harmony.Patch(saveWholeBackup, new HarmonyMethod(prefix), new HarmonyMethod(postfix));
}
/*********
** Private methods
*********/
/// <summary>The method to call instead of <see cref="StardewValley.Object.getDescription"/>.</summary>
/// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
private static void Prefix()
{
SaveBackupPatch.Events.Saving.RaiseEmpty();
}
private static void PostFix()
{
SaveBackupPatch.Events.Saved.RaiseEmpty();
}
}
}

View File

@ -24,6 +24,8 @@ namespace StardewModdingAPI
private SpriteFont smallFont;
private Vector2 size;
private bool scrolling = false;
internal SGameConsole()
@ -40,11 +42,14 @@ namespace StardewModdingAPI
this.scrollbox = new MobileScrollbox(0, 0, 1280, 320, this.consoleMessageQueue.Count, new Rectangle(0, 0, 1280, 320));
this.textBoxBounds = new Rectangle(this.textBox.X, this.textBox.Y, this.textBox.Width, this.textBox.Height);
this.scrollbox.Bounds = this.textBoxBounds;
}
internal void InitializeContent(LocalizedContentManager content)
{
this.smallFont = content.Load<SpriteFont>(@"Fonts\SmallFont");
this.size = this.smallFont.MeasureString("aA");
}
public void Show()
@ -104,13 +109,16 @@ namespace StardewModdingAPI
public override void draw(SpriteBatch b)
{
Vector2 size = this.smallFont.MeasureString("aA");
float y = Game1.game1.screen.Height - size.Y * 2;
float y = Game1.game1.screen.Height - this.size.Y;
lock (this.consoleMessageQueue)
{
foreach (var log in this.consoleMessageQueue)
{
string text = log.Value;
if (text.Length > 125)
{
text = text.Insert(125, "\n");
}
switch (log.Key)
{
case ConsoleLogLevel.Critical:
@ -134,12 +142,12 @@ namespace StardewModdingAPI
break;
}
size = this.smallFont.MeasureString(text);
this.size = this.smallFont.MeasureString(text);
if (y < 0)
{
break;
}
y -= size.Y;
y -= this.size.Y;
}
}
}

View File

@ -17,55 +17,30 @@ using StardewModdingAPI.Framework;
using StardewValley;
using Android.Widget;
using System.Reflection;
using Microsoft.Xna.Framework;
namespace StardewModdingAPI
{
[Activity(Label = "Stardew Valley", Icon = "@mipmap/ic_launcher", Theme = "@style/Theme.Splash", MainLauncher = false, AlwaysRetainTaskState = true, LaunchMode = LaunchMode.SingleInstance, ScreenOrientation = ScreenOrientation.SensorLandscape, ConfigurationChanges = (ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.Orientation | ConfigChanges.ScreenLayout | ConfigChanges.ScreenSize | ConfigChanges.UiMode))]
[Activity(Label = "Stardew Valley", Icon = "@mipmap/ic_launcher", Theme = "@style/Theme.Splash", MainLauncher = true, AlwaysRetainTaskState = true, LaunchMode = LaunchMode.SingleInstance, ScreenOrientation = ScreenOrientation.SensorLandscape, ConfigurationChanges = (ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.Orientation | ConfigChanges.ScreenLayout | ConfigChanges.ScreenSize | ConfigChanges.UiMode))]
public class SMainActivity: MainActivity, ILicenseCheckerCallback, IJavaObject, IDisposable, IDownloaderClient
{
[Service]
public class ExpansionDownloaderService : DownloaderService
{
public override string PublicKey => "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAry4fecehDpCohQk4XhiIZX9ylIGUThWZxfN9qwvQyTh53hvnpQl/lCrjfflKoPz6gz5jJn6JI1PTnoBy/iXVx1+kbO99qBgJE2V8PS5pq+Usbeqqmqqzx4lEzhiYQ2um92v4qkldNYZFwbTODYPIMbSbaLm7eK9ZyemaRbg9ssAl4QYs0EVxzDK1DjuXilRk28WxiK3lNJTz4cT38bfs4q6Zvuk1vWUvnMqcxiugox6c/9j4zZS5C4+k+WY6mHjUMuwssjCY3G+aImWDSwnU3w9G41q8EoPvJ1049PIi7GJXErusTYZITmqfonyejmSFLPt8LHtux9AmJgFSrC3UhwIDAQAB";
public override string AlarmReceiverClassName => Class.FromType(typeof(ExpansionDownloaderReceiver)).CanonicalName;
public override byte[] GetSalt()
{
return new byte[15]
{
98,
100,
12,
43,
2,
8,
4,
9,
5,
106,
108,
33,
45,
1,
84
};
}
}
[BroadcastReceiver(Exported = false)]
public class ExpansionDownloaderReceiver : BroadcastReceiver
{
public override void OnReceive(Android.Content.Context context, Intent intent)
{
DownloaderService.StartDownloadServiceIfRequired(context, intent, typeof(ExpansionDownloaderService));
}
}
private SCore core;
private LicenseChecker _licenseChecker;
private PowerManager.WakeLock _wakeLock;
private Action _callback;
public new bool HasPermissions
{
get
{
return this.PackageManager.CheckPermission("android.permission.ACCESS_NETWORK_STATE", this.PackageName) == Permission.Granted
&& this.PackageManager.CheckPermission("android.permission.ACCESS_WIFI_STATE", this.PackageName) == Permission.Granted
&& this.PackageManager.CheckPermission("android.permission.INTERNET", this.PackageName) == Permission.Granted
&& this.PackageManager.CheckPermission("android.permission.READ_EXTERNAL_STORAGE", this.PackageName) == Permission.Granted
&& this.PackageManager.CheckPermission("android.permission.VIBRATE", this.PackageName) == Permission.Granted
&& this.PackageManager.CheckPermission("android.permission.WAKE_LOCK", this.PackageName) == Permission.Granted
&& this.PackageManager.CheckPermission("android.permission.WRITE_EXTERNAL_STORAGE", this.PackageName) == Permission.Granted
&& this.PackageManager.CheckPermission("com.android.vending.CHECK_LICENSE", this.PackageName) == Permission.Granted;
}
}
private string[] requiredPermissions => new string[8]
{
@ -79,7 +54,7 @@ namespace StardewModdingAPI
"com.android.vending.CHECK_LICENSE"
};
private string[] deniedPermissionsArray
private string[] DeniedPermissionsArray
{
get
{
@ -109,19 +84,16 @@ namespace StardewModdingAPI
PowerManager powerManager = (PowerManager)this.GetSystemService("power");
this._wakeLock = powerManager.NewWakeLock(WakeLockFlags.Full, "StardewWakeLock");
this._wakeLock.Acquire();
typeof(MainActivity).GetField("_wakeLock", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(this, this._wakeLock);
base.OnCreate(bundle);
if (!base.HasPermissions)
{
base.PromptForPermissions();
}
this.OnCreatePartTwo();
this.CheckAppPermissions();
}
public void OnCreatePartTwo()
{
typeof(MainActivity).GetMethod("SetZoomScaleAndMenuButtonScale")?.Invoke(this, null);
typeof(MainActivity).GetMethod("SetSavesPath")?.Invoke(this, null);
base.SetPaddingForMenus();
this.SetPaddingForMenus();
Toast.MakeText(context: this, "Initializing SMAPI", ToastLength.Long).Show();
new SGameConsole();
@ -129,14 +101,28 @@ namespace StardewModdingAPI
Program.Main(null);
this.core = new SCore(System.IO.Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, "StardewValley/Mods"), false);
this.core.RunInteractively();
typeof(MainActivity).GetField("_game1", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(this, this.core.GameInstance);
this.SetContentView((View)this.core.GameInstance.Services.GetService(typeof(View)));
this.core.GameInstance.Run();
//this.core.GameInstance.Run();
this.CheckUsingServerManagedPolicy();
}
public new void CheckAppPermissions()
{
if (!this.HasPermissions)
this.PromptForPermissions();
this.OnCreatePartTwo();
}
public new void PromptForPermissions()
{
ActivityCompat.RequestPermissions(this, this.DeniedPermissionsArray, 0);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
if (permissions.Length == 0)
@ -172,12 +158,6 @@ namespace StardewModdingAPI
}
if (num == permissions.Length)
{
if (this._callback != null)
{
this._callback();
this._callback = null;
return;
}
this.OnCreatePartTwo();
}
}

View File

@ -295,6 +295,9 @@
<Compile Include="Framework\Reflection\ReflectedProperty.cs" />
<Compile Include="Framework\Reflection\Reflector.cs" />
<Compile Include="Framework\RequestExitDelegate.cs" />
<Compile Include="Framework\RewriteFacades\DebrisMethods.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Framework\RewriteFacades\GameLocationMethods.cs" />
<Compile Include="Framework\RewriteFacades\ItemGrabMenuMethods.cs" />
<Compile Include="Framework\RewriteFacades\NPCMethods.cs" />
@ -307,6 +310,7 @@
<Compile Include="Framework\RewriteFacades\FarmerRenderMethods.cs" />
<Compile Include="Framework\RewriteFacades\FarmerMethods.cs" />
<Compile Include="Framework\RewriteFacades\SpriteBatchMethods.cs" />
<Compile Include="Framework\RewriteFacades\WeatherDebrisMethods.cs" />
<Compile Include="Framework\SCore.cs" />
<Compile Include="Framework\Serialisation\ColorConverter.cs" />
<Compile Include="Framework\Serialisation\PointConverter.cs" />
@ -372,6 +376,7 @@
<Compile Include="Patches\DialogueErrorPatch.cs" />
<Compile Include="Patches\LoadForNewGamePatch.cs" />
<Compile Include="Patches\ObjectErrorPatch.cs" />
<Compile Include="Patches\SaveBackupPatch.cs" />
<Compile Include="PatchMode.cs" />
<Compile Include="Program.cs" />
<Compile Include="Resources\Resource.designer.cs" />

View File

@ -14,7 +14,6 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
private readonly IModHelper helper;
private readonly IMonitor Monitor;
private readonly Rectangle buttonRectangle;
private readonly int padding;
private object buttonPressed;
private object buttonReleased;
@ -26,8 +25,9 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
private readonly MethodBase Legacy_KeyPressed;
private readonly MethodBase Legacy_KeyReleased;
private readonly SButton button;
private readonly SButton buttonKey;
private readonly float transparency;
private readonly string alias;
public bool hidden;
private bool raisingPressed = false;
private bool raisingReleased = false;
@ -38,8 +38,13 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
this.helper = helper;
this.hidden = true;
this.buttonRectangle = new Rectangle(buttonDefine.rectangle.X, buttonDefine.rectangle.Y, buttonDefine.rectangle.Width, buttonDefine.rectangle.Height);
this.padding = buttonDefine.rectangle.Padding;
this.button = buttonDefine.key;
this.buttonKey = buttonDefine.key;
if (buttonDefine.alias == null)
this.alias = this.buttonKey.ToString();
else
this.alias = buttonDefine.alias;
if (buttonDefine.transparency <= 0.01f || buttonDefine.transparency > 1f)
{
buttonDefine.transparency = 0.5f;
@ -67,20 +72,22 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
this.Legacy_KeyReleased = this.legacyButtonReleased.GetType().GetMethod("Raise", BindingFlags.Public | BindingFlags.Instance);
}
private bool shouldTrigger(Vector2 point)
private bool shouldTrigger()
{
int nativeZoomLevel = (int)Game1.NativeZoomLevel;
int x1;
int y1;
try
if (nativeZoomLevel != 0)
{
x1 = Mouse.GetState().X / nativeZoomLevel;
y1 = Mouse.GetState().Y / nativeZoomLevel;
}
else
{
x1 = (int)((float)Mouse.GetState().X / Game1.NativeZoomLevel);
y1 = (int)((float)Mouse.GetState().Y / Game1.NativeZoomLevel);
}
catch
{
x1 = (int)point.X;
y1 = (int)point.Y;
}
if (this.buttonRectangle.Contains(x1, y1))
{
return true;
@ -94,13 +101,13 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
{
return;
}
Vector2 point = e.Cursor.ScreenPixels;
if (this.shouldTrigger(point) && !this.hidden)
if (this.shouldTrigger() && !this.hidden)
{
object inputState = e.GetType().GetField("InputState", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(e);
object buttonPressedEventArgs = Activator.CreateInstance(typeof(ButtonPressedEventArgs), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { this.button, e.Cursor, inputState }, null);
EventArgsKeyPressed eventArgsKey = new EventArgsKeyPressed((Keys)this.button);
object buttonPressedEventArgs = Activator.CreateInstance(typeof(ButtonPressedEventArgs), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { this.buttonKey, e.Cursor, inputState }, null);
EventArgsKeyPressed eventArgsKey = new EventArgsKeyPressed((Keys)this.buttonKey);
try
{
this.raisingPressed = true;
@ -121,12 +128,12 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
{
return;
}
Vector2 point = e.Cursor.ScreenPixels;
if (this.shouldTrigger(point))
if (this.shouldTrigger())
{
object inputState = e.GetType().GetField("InputState", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(e);
object buttonReleasedEventArgs = Activator.CreateInstance(typeof(ButtonReleasedEventArgs), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { this.button, e.Cursor, inputState }, null);
EventArgsKeyPressed eventArgsKeyReleased = new EventArgsKeyPressed((Keys)this.button);
object buttonReleasedEventArgs = Activator.CreateInstance(typeof(ButtonReleasedEventArgs), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { this.buttonKey, e.Cursor, inputState }, null);
EventArgsKeyPressed eventArgsKeyReleased = new EventArgsKeyPressed((Keys)this.buttonKey);
try
{
this.raisingReleased = true;
@ -145,9 +152,9 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
/// <param name="e">The event arguments.</param>
private void OnRenderingHud(object sender, EventArgs e)
{
if (!Game1.eventUp && !this.hidden && Game1.activeClickableMenu is GameMenu == false)
if (!Game1.eventUp && !this.hidden && Game1.activeClickableMenu is GameMenu == false && Game1.activeClickableMenu is ShopMenu == false)
{
IClickableMenu.drawButtonWithText(Game1.spriteBatch, Game1.smallFont, this.button.ToString(), this.buttonRectangle.X, this.buttonRectangle.Y, this.buttonRectangle.Width, this.buttonRectangle.Height, Color.BurlyWood * this.transparency);
IClickableMenu.drawButtonWithText(Game1.spriteBatch, Game1.smallFont, this.alias, this.buttonRectangle.X, this.buttonRectangle.Y, this.buttonRectangle.Width, this.buttonRectangle.Height, Color.BurlyWood * this.transparency);
}
}
}

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StardewValley;
using StardewValley.Menus;
namespace StardewModdingAPI.Mods.VirtualKeyboard
{
@ -20,11 +21,13 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
public SButton key;
public Rect rectangle;
public float transparency;
public VirtualButton(SButton key, Rect rectangle, float transparency)
public string alias;
public VirtualButton(SButton key, Rect rectangle, float transparency, string alias = null)
{
this.key = key;
this.rectangle = rectangle;
this.transparency = transparency;
this.alias = alias;
}
}
internal class Rect

View File

@ -10,7 +10,7 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
{
public override void Entry(IModHelper helper)
{
VirtualToggle virtualToggle = new VirtualToggle(helper, this.Monitor);
new VirtualToggle(helper, this.Monitor);
}
}
}

View File

@ -78,17 +78,17 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VirtualToggle.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StardewModdingAPI\StardewModdingAPI.csproj">
<Project>{9898b56e-51eb-40cf-8b1f-aceb4b6397a7}</Project>
<Name>StardewModdingAPI</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="manifest.json" />
</ItemGroup>
<ItemGroup>
<Content Include="assets\togglebutton.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SMAPI\StardewModdingAPI.csproj">
<Project>{9898b56e-51eb-40cf-8b1f-aceb4b6397a7}</Project>
<Name>StardewModdingAPI</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -5,9 +5,7 @@ using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Locations;
using StardewValley.Menus;
using StardewValley.Mobile;
namespace StardewModdingAPI.Mods.VirtualKeyboard
{
@ -28,7 +26,7 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
this.Monitor = monitor;
this.helper = helper;
this.texture = this.helper.Content.Load<Texture2D>("assets/togglebutton.png", ContentSource.ModFolder);
this.virtualToggleButton = new ClickableTextureComponent(new Rectangle(Game1.toolbarPaddingX + 36, 12, 64, 64), this.texture, new Rectangle(0, 0, 16, 16), 5.75f, false);
this.virtualToggleButton = new ClickableTextureComponent(new Rectangle(Game1.virtualJoypad.buttonToggleJoypad.bounds.X + 36, 12, 64, 64), this.texture, new Rectangle(0, 0, 16, 16), 5.75f, false);
this.modConfig = helper.ReadConfig<ModConfig>();
for (int i = 0; i < this.modConfig.buttons.Length; i++)
@ -36,7 +34,6 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
this.keyboard.Add(new KeyButton(helper, this.modConfig.buttons[i], this.Monitor));
}
helper.WriteConfig(this.modConfig);
this.helper.Events.Display.RenderingHud += this.OnRenderingHUD;
this.helper.Events.Input.ButtonPressed += this.VirtualToggleButtonPressed;
this.helper.Events.Input.ButtonReleased += this.VirtualToggleButtonReleased;
@ -44,12 +41,11 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
private void VirtualToggleButtonPressed(object sender, ButtonPressedEventArgs e)
{
Vector2 point = e.Cursor.ScreenPixels;
if (!this.enabled && this.shouldTrigger(point))
if (!this.enabled && this.shouldTrigger())
{
this.hiddenKeys(true, false);
}
else if (this.enabled && this.shouldTrigger(point))
else if (this.enabled && this.shouldTrigger())
{
this.hiddenKeys(false, true);
if (Game1.activeClickableMenu is IClickableMenu menu)
@ -68,21 +64,22 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
}
}
private bool shouldTrigger(Vector2 point)
private bool shouldTrigger()
{
int nativeZoomLevel = (int)Game1.NativeZoomLevel;
int x1;
int y1;
try
if (nativeZoomLevel != 0)
{
x1 = Mouse.GetState().X / nativeZoomLevel;
y1 = Mouse.GetState().Y / nativeZoomLevel;
}
else
{
x1 = (int)((float)Mouse.GetState().X / Game1.NativeZoomLevel);
y1 = (int)((float)Mouse.GetState().Y / Game1.NativeZoomLevel);
}
catch
{
x1 = (int)point.X;
y1 = (int)point.Y;
this.Monitor.Log("Game1 Zoom Level: " + (int)Game1.NativeZoomLevel);
}
if (this.virtualToggleButton.containsPoint(x1, y1))
{
Toolbar.toolbarPressed = true;
@ -101,13 +98,23 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
this.virtualToggleButton.bounds.X = Game1.toolbarPaddingX + Game1.toolbar.itemSlotSize + 150;
else
this.virtualToggleButton.bounds.X = Game1.toolbarPaddingX + Game1.toolbar.itemSlotSize + 50;
if (Game1.toolbar.alignTop == true && !Game1.options.verticalToolbar)
{
object toolbarHeight = this.helper.Reflection.GetField<int>(Game1.toolbar, "toolbarHeight").GetValue();
this.virtualToggleButton.bounds.Y = (int)toolbarHeight + 50;
}
else
{
this.virtualToggleButton.bounds.Y = 10;
}
float scale = 1f;
if (!this.enabled)
{
scale = 0.5f;
}
if(!Game1.eventUp && Game1.activeClickableMenu is GameMenu == false)
if(!Game1.eventUp && Game1.activeClickableMenu is GameMenu == false && Game1.activeClickableMenu is ShopMenu == false)
this.virtualToggleButton.draw(Game1.spriteBatch, Color.White * scale, 0.000001f);
}
}

View File

@ -1,7 +1,7 @@
{
"Name": "VirtualKeyboard",
"Author": "MartyrPher",
"Version": "0.8.9",
"Version": "0.9.4",
"MinimumApiVersion": "2.10.1",
"Description": "A much needed Virtual Keyboard for SMAPI Android.",
"UniqueID": "VirtualKeyboard",