From 8fc324a86a5ef454a9186cabc890a7e726c1dd41 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 2 Jul 2019 18:57:53 -0400 Subject: [PATCH] Rewrites, added harmony patch, VK fix --- src/SMAPI.sln | 12 +-- src/SMAPI/Constants.cs | 3 + .../TypeFieldToAnotherTypeFieldRewriter.cs | 47 ++++++++-- src/SMAPI/Framework/Patching/GamePatcher.cs | 8 +- .../Framework/RewriteFacades/DebrisMethods.cs | 83 ++++++++++++++++ .../Framework/RewriteFacades/FarmerMethods.cs | 10 +- .../RewriteFacades/FarmerRenderMethods.cs | 2 +- .../Framework/RewriteFacades/Game1Methods.cs | 17 ++++ .../RewriteFacades/GameLocationMethods.cs | 8 +- .../RewriteFacades/SpriteTextMethods.cs | 7 +- .../RewriteFacades/WeatherDebrisMethods.cs | 17 ++++ src/SMAPI/Framework/SCore.cs | 14 +-- src/SMAPI/Framework/SGame.cs | 14 ++- src/SMAPI/Metadata/InstructionMetadata.cs | 12 ++- src/SMAPI/Patches/SaveBackupPatch.cs | 67 +++++++++++++ src/SMAPI/SGameConsole.cs | 18 +++- src/SMAPI/SMainActivity.cs | 94 ++++++++----------- src/SMAPI/StardewModdingAPI.csproj | 5 + .../KeyButton.cs | 49 +++++----- .../ModConfig.cs | 5 +- .../ModEntry.cs | 2 +- ...rdewModdingAPI.Mods.VirtualKeyboard.csproj | 12 +-- .../VirtualToggle.cs | 43 +++++---- .../manifest.json | 2 +- 24 files changed, 401 insertions(+), 150 deletions(-) create mode 100644 src/SMAPI/Framework/RewriteFacades/DebrisMethods.cs create mode 100644 src/SMAPI/Framework/RewriteFacades/WeatherDebrisMethods.cs create mode 100644 src/SMAPI/Patches/SaveBackupPatch.cs diff --git a/src/SMAPI.sln b/src/SMAPI.sln index aa4e23a8..59067b8a 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -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 diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 59ebc2b0..a72fd54e 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -22,6 +22,9 @@ namespace StardewModdingAPI /// SMAPI's current semantic version. public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.11.2"); + /// Android SMAPI's current semantic version. + public static ISemanticVersion AndroidApiVersion { get; } = new Toolkit.SemanticVersion("0.8.7"); + /// The minimum supported version of Stardew Valley. public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.36"); diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/TypeFieldToAnotherTypeFieldRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/TypeFieldToAnotherTypeFieldRewriter.cs index 1ca84ac0..b1aad322 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/TypeFieldToAnotherTypeFieldRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/TypeFieldToAnotherTypeFieldRewriter.cs @@ -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 /// The type whose field to which references should be rewritten. /// The field name to rewrite. /// The property name (if different). - 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; } /// Construct an instance. /// The type whose field to which references should be rewritten. /// The field name to rewrite. - 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) { } /// Perform the predefined logic for an instruction if applicable. /// The assembly module containing the instruction. @@ -61,14 +67,39 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters if (!this.IsMatch(instruction)) return InstructionHandleResult.None; - //string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get"; try { - MethodReference method = module.ImportReference(this.ToType.GetMethod($"get_{this.PropertyName}")); - FieldReference field = module.ImportReference(this.ToType.GetField(this.FieldName)); + 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)); - cil.InsertAfter(instruction, cil.Create(OpCodes.Ldfld, field)); - cil.Replace(instruction, cil.Create(OpCodes.Call, method)); + 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) { diff --git a/src/SMAPI/Framework/Patching/GamePatcher.cs b/src/SMAPI/Framework/Patching/GamePatcher.cs index 8aaae5c9..9ba5f960 100644 --- a/src/SMAPI/Framework/Patching/GamePatcher.cs +++ b/src/SMAPI/Framework/Patching/GamePatcher.cs @@ -29,7 +29,7 @@ namespace StardewModdingAPI.Framework.Patching /// The patches to apply. public void Apply(params IHarmonyPatch[] patches) { - if(Build.VERSION.SdkInt > BuildVersionCodes.LollipopMr1) + if (Build.VERSION.SdkInt > BuildVersionCodes.LollipopMr1) { HarmonyDetourBridge.Init(); @@ -46,7 +46,11 @@ namespace StardewModdingAPI.Framework.Patching this.Monitor.Log(ex.GetLogSummary(), LogLevel.Trace); } } - } + } + else + { + this.Monitor.Log("Harmony mods are not supported on this Android Version."); + } } } } diff --git a/src/SMAPI/Framework/RewriteFacades/DebrisMethods.cs b/src/SMAPI/Framework/RewriteFacades/DebrisMethods.cs new file mode 100644 index 00000000..fdb67e02 --- /dev/null +++ b/src/SMAPI/Framework/RewriteFacades/DebrisMethods.cs @@ -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); + } + } +} diff --git a/src/SMAPI/Framework/RewriteFacades/FarmerMethods.cs b/src/SMAPI/Framework/RewriteFacades/FarmerMethods.cs index fa8f0f85..39da4768 100644 --- a/src/SMAPI/Framework/RewriteFacades/FarmerMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/FarmerMethods.cs @@ -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() diff --git a/src/SMAPI/Framework/RewriteFacades/FarmerRenderMethods.cs b/src/SMAPI/Framework/RewriteFacades/FarmerRenderMethods.cs index ccd63210..22c55c57 100644 --- a/src/SMAPI/Framework/RewriteFacades/FarmerRenderMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/FarmerRenderMethods.cs @@ -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); } } } diff --git a/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs b/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs index 92a54819..0aeaa1e6 100644 --- a/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs +++ b/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs @@ -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).ToArray(); + public new IList onScreenMenus = Game1.onScreenMenus; + + public static void updateDebrisWeatherForMovement(List 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); + } } } diff --git a/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs b/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs index aff28ddf..d9114ae4 100644 --- a/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs @@ -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); - // } - + { } } diff --git a/src/SMAPI/Framework/RewriteFacades/SpriteTextMethods.cs b/src/SMAPI/Framework/RewriteFacades/SpriteTextMethods.cs index e38888c2..34cac028 100644 --- a/src/SMAPI/Framework/RewriteFacades/SpriteTextMethods.cs +++ b/src/SMAPI/Framework/RewriteFacades/SpriteTextMethods.cs @@ -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); } } } diff --git a/src/SMAPI/Framework/RewriteFacades/WeatherDebrisMethods.cs b/src/SMAPI/Framework/RewriteFacades/WeatherDebrisMethods.cs new file mode 100644 index 00000000..229667e0 --- /dev/null +++ b/src/SMAPI/Framework/RewriteFacades/WeatherDebrisMethods.cs @@ -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) + { + } + } +} diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index e48de1d6..90247768 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -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 { diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 57380d0a..1fa894ea 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -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) { diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 4de85ece..9b157968 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -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(typeof(Game1), "tileSize", Game1.tileSize); - //yield return new TypeReferenceRewriter("System.Collections.Generic.IList`1", typeof(List)); yield return new FieldToPropertyRewriter(typeof(Game1), "player"); yield return new FieldToPropertyRewriter(typeof(Game1), "currentLocation"); yield return new FieldToPropertyRewriter(typeof(Character), "currentLocation"); diff --git a/src/SMAPI/Patches/SaveBackupPatch.cs b/src/SMAPI/Patches/SaveBackupPatch.cs new file mode 100644 index 00000000..2669d03b --- /dev/null +++ b/src/SMAPI/Patches/SaveBackupPatch.cs @@ -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 + *********/ + /// A unique name for this patch. + public string Name => $"{nameof(SaveBackupPatch)}"; + + /// An Instance of . + private static EventManager Events; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// SMAPI's EventManager Instance + + public SaveBackupPatch(EventManager eventManager) + { + SaveBackupPatch.Events = eventManager; + } + + + + /// Apply the Harmony patch. + /// The Harmony instance. + 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 + *********/ + /// The method to call instead of . + /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. + [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(); + } + } +} diff --git a/src/SMAPI/SGameConsole.cs b/src/SMAPI/SGameConsole.cs index 665bd5fe..4b786c4e 100644 --- a/src/SMAPI/SGameConsole.cs +++ b/src/SMAPI/SGameConsole.cs @@ -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(@"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: @@ -133,13 +141,13 @@ namespace StardewModdingAPI b.DrawString(this.smallFont, text, new Vector2(16, y), Color.LightGray); break; } - - size = this.smallFont.MeasureString(text); + + this.size = this.smallFont.MeasureString(text); if (y < 0) { break; } - y -= size.Y; + y -= this.size.Y; } } } diff --git a/src/SMAPI/SMainActivity.cs b/src/SMAPI/SMainActivity.cs index 699011fc..b17ce3d2 100644 --- a/src/SMAPI/SMainActivity.cs +++ b/src/SMAPI/SMainActivity.cs @@ -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(); - this.SetContentView((View)this.core.GameInstance.Services.GetService(typeof(View))); - this.core.GameInstance.Run(); + 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.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(); } } diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index eec92e23..4ef2626e 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -295,6 +295,9 @@ + + Code + @@ -307,6 +310,7 @@ + @@ -372,6 +376,7 @@ + diff --git a/src/StardewModdingAPI.Mods.VirtualKeyboard/KeyButton.cs b/src/StardewModdingAPI.Mods.VirtualKeyboard/KeyButton.cs index 40ab1e01..fea590a0 100644 --- a/src/StardewModdingAPI.Mods.VirtualKeyboard/KeyButton.cs +++ b/src/StardewModdingAPI.Mods.VirtualKeyboard/KeyButton.cs @@ -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 /// The event arguments. 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); } } } diff --git a/src/StardewModdingAPI.Mods.VirtualKeyboard/ModConfig.cs b/src/StardewModdingAPI.Mods.VirtualKeyboard/ModConfig.cs index 7076c6dc..7930b64f 100644 --- a/src/StardewModdingAPI.Mods.VirtualKeyboard/ModConfig.cs +++ b/src/StardewModdingAPI.Mods.VirtualKeyboard/ModConfig.cs @@ -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 diff --git a/src/StardewModdingAPI.Mods.VirtualKeyboard/ModEntry.cs b/src/StardewModdingAPI.Mods.VirtualKeyboard/ModEntry.cs index af506b4c..06ac1de8 100644 --- a/src/StardewModdingAPI.Mods.VirtualKeyboard/ModEntry.cs +++ b/src/StardewModdingAPI.Mods.VirtualKeyboard/ModEntry.cs @@ -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); } } } diff --git a/src/StardewModdingAPI.Mods.VirtualKeyboard/StardewModdingAPI.Mods.VirtualKeyboard.csproj b/src/StardewModdingAPI.Mods.VirtualKeyboard/StardewModdingAPI.Mods.VirtualKeyboard.csproj index b94b1609..75b73842 100644 --- a/src/StardewModdingAPI.Mods.VirtualKeyboard/StardewModdingAPI.Mods.VirtualKeyboard.csproj +++ b/src/StardewModdingAPI.Mods.VirtualKeyboard/StardewModdingAPI.Mods.VirtualKeyboard.csproj @@ -78,17 +78,17 @@ - - - {9898b56e-51eb-40cf-8b1f-aceb4b6397a7} - StardewModdingAPI - - + + + {9898b56e-51eb-40cf-8b1f-aceb4b6397a7} + StardewModdingAPI + + \ No newline at end of file diff --git a/src/StardewModdingAPI.Mods.VirtualKeyboard/VirtualToggle.cs b/src/StardewModdingAPI.Mods.VirtualKeyboard/VirtualToggle.cs index 5586e293..8e4acdb1 100644 --- a/src/StardewModdingAPI.Mods.VirtualKeyboard/VirtualToggle.cs +++ b/src/StardewModdingAPI.Mods.VirtualKeyboard/VirtualToggle.cs @@ -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("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(); 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,18 +41,17 @@ 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) { menu.exitThisMenu(); - } + } } } @@ -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; - this.virtualToggleButton.bounds.Y = 10; + + if (Game1.toolbar.alignTop == true && !Game1.options.verticalToolbar) + { + object toolbarHeight = this.helper.Reflection.GetField(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); } } diff --git a/src/StardewModdingAPI.Mods.VirtualKeyboard/manifest.json b/src/StardewModdingAPI.Mods.VirtualKeyboard/manifest.json index 9023562e..4ccd8045 100644 --- a/src/StardewModdingAPI.Mods.VirtualKeyboard/manifest.json +++ b/src/StardewModdingAPI.Mods.VirtualKeyboard/manifest.json @@ -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",