diff --git a/src/SMAPI.Mods.VirtualKeyboard/KeyButton.cs b/src/SMAPI.Mods.VirtualKeyboard/KeyButton.cs index c6f43b04..7fc1d6bd 100644 --- a/src/SMAPI.Mods.VirtualKeyboard/KeyButton.cs +++ b/src/SMAPI.Mods.VirtualKeyboard/KeyButton.cs @@ -1,74 +1,58 @@ using System; -using System.Collections.Concurrent; +using System.Reflection; +using System.Threading.Tasks; using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; using StardewModdingAPI.Events; +using StardewModdingAPI.Framework; +using StardewModdingAPI.Framework.Input; using StardewValley; using StardewValley.Menus; -using System.Reflection; -using Microsoft.Xna.Framework.Input; using static StardewModdingAPI.Mods.VirtualKeyboard.ModConfig; -using System.Threading.Tasks; -using Microsoft.Xna.Framework.Graphics; namespace StardewModdingAPI.Mods.VirtualKeyboard { class KeyButton { - private readonly IModHelper helper; - private readonly IMonitor Monitor; - private readonly Rectangle buttonRectangle; + private readonly Rectangle ButtonRectangle; - private object buttonPressed; - private object buttonReleased; - - private readonly MethodBase RaiseButtonPressed; - private readonly MethodBase RaiseButtonReleased; - - private readonly SButton buttonKey; - private readonly float transparency; - private readonly string alias; - private readonly string command; - public bool hidden; - private bool raisingPressed = false; - private bool raisingReleased = false; + private readonly SButton ButtonKey; + private readonly float Transparency; + private readonly string Alias; + private readonly string Command; + public bool Hidden; + private bool RaisingPressed; + private bool RaisingReleased; public KeyButton(IModHelper helper, VirtualButton buttonDefine, IMonitor monitor) { - this.Monitor = monitor; - this.helper = helper; - this.hidden = true; - this.buttonRectangle = new Rectangle(buttonDefine.rectangle.X, buttonDefine.rectangle.Y, buttonDefine.rectangle.Width, buttonDefine.rectangle.Height); - this.buttonKey = buttonDefine.key; + this.Hidden = true; + this.ButtonRectangle = new Rectangle(buttonDefine.rectangle.X, buttonDefine.rectangle.Y, buttonDefine.rectangle.Width, buttonDefine.rectangle.Height); + this.ButtonKey = buttonDefine.key; if (buttonDefine.alias == null) - this.alias = this.buttonKey.ToString(); + this.Alias = this.ButtonKey.ToString(); else - this.alias = buttonDefine.alias; - this.command = buttonDefine.command; + this.Alias = buttonDefine.alias; + this.Command = buttonDefine.command; if (buttonDefine.transparency <= 0.01f || buttonDefine.transparency > 1f) { buttonDefine.transparency = 0.5f; } - this.transparency = buttonDefine.transparency; + this.Transparency = buttonDefine.transparency; helper.Events.Display.Rendered += this.OnRendered; helper.Events.Input.ButtonReleased += this.EventInputButtonReleased; helper.Events.Input.ButtonPressed += this.EventInputButtonPressed; } - private object GetSCore(IModHelper helper) + private bool ShouldTrigger(Vector2 screenPixels, SButton button) { - MainActivity activity = this.helper.Reflection.GetField(typeof(MainActivity), "instance").GetValue(); - object score = activity.GetType().GetField("core", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(activity); - return score; - } - - private bool shouldTrigger(Vector2 screenPixels, SButton button) - { - if (this.buttonRectangle.Contains(screenPixels.X * Game1.options.zoomLevel, screenPixels.Y * Game1.options.zoomLevel) && !this.hidden && button == SButton.MouseLeft) + if (this.ButtonRectangle.Contains(screenPixels.X * Game1.options.zoomLevel, screenPixels.Y * Game1.options.zoomLevel) && !this.Hidden && button == SButton.MouseLeft) { - if (!this.hidden) + if (!this.Hidden) Toolbar.toolbarPressed = true; return true; } @@ -77,34 +61,34 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard private void EventInputButtonPressed(object sender, ButtonPressedEventArgs e) { - if (this.raisingPressed) + if (this.RaisingPressed) { return; } Vector2 screenPixels = e.Cursor.ScreenPixels; - if (this.buttonKey != SButton.None && this.shouldTrigger(screenPixels, e.Button)) + if (this.ButtonKey != SButton.None && this.ShouldTrigger(screenPixels, e.Button)) { - object input = this.helper.Reflection.GetField(typeof(Game1), "input").GetValue(); - this.raisingPressed = true; - input.GetType().GetMethod("OverrideButton").Invoke(input, new object[] { this.buttonKey, true }); - this.raisingPressed = false; + this.RaisingPressed = true; + SInputState input = Game1.input as SInputState; + input?.OverrideButton(this.ButtonKey, true); + this.RaisingPressed = false; } } private void EventInputButtonReleased(object sender, ButtonReleasedEventArgs e) { - if (this.raisingReleased) + if (this.RaisingReleased) { return; } Vector2 screenPixels = e.Cursor.ScreenPixels; - if (this.shouldTrigger(screenPixels, e.Button)) + if (this.ShouldTrigger(screenPixels, e.Button)) { - if (this.buttonKey == SButton.RightWindows) + if (this.ButtonKey == SButton.RightWindows) { - KeyboardInput.Show("Command", "", "", false).ContinueWith(delegate (Task s) { + KeyboardInput.Show("Command", "").ContinueWith(delegate (Task s) { string command; command = s.Result; if (command.Length > 0) @@ -115,36 +99,31 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard }); return; } - if (this.buttonKey == SButton.RightControl) + if (this.ButtonKey == SButton.RightControl) { SGameConsole.Instance.Show(); return; } - if (!string.IsNullOrEmpty(this.command)) + if (!string.IsNullOrEmpty(this.Command)) { - this.SendCommand(this.command); + this.SendCommand(this.Command); return; } - object input = this.helper.Reflection.GetField(typeof(Game1), "input").GetValue(); - this.raisingReleased = true; - input.GetType().GetMethod("OverrideButton").Invoke(input, new object[] { this.buttonKey, false }); - this.raisingReleased = false; + this.RaisingReleased = true; + SInputState input = Game1.input as SInputState; + input?.OverrideButton(this.ButtonKey, false); + this.RaisingReleased = false; } } private void SendCommand(string command) { - object score = this.GetSCore(this.helper); - ConcurrentQueue commandQueue = score.GetType().GetProperty("CommandQueue", BindingFlags.Public | BindingFlags.Instance)?.GetValue(score) as ConcurrentQueue; + SCore score = SMainActivity.Instance.core; + CommandQueue commandQueue = score.RawCommandQueue; if (commandQueue != null) { - commandQueue.Enqueue(command); - return; + commandQueue.Add(command); } - - object sgame = score.GetType().GetField("Game", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(score); - commandQueue = sgame.GetType().GetProperty("CommandQueue", BindingFlags.Public | BindingFlags.Instance)?.GetValue(sgame) as ConcurrentQueue; - commandQueue?.Enqueue(command); } /// Raised before drawing the HUD (item toolbar, clock, etc) to the screen. @@ -152,19 +131,20 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard /// The event arguments. private void OnRendered(object sender, EventArgs e) { - if (!this.hidden) + if (!this.Hidden) { - float scale = this.transparency; + float scale = this.Transparency; if (!Game1.eventUp && Game1.activeClickableMenu is GameMenu == false && Game1.activeClickableMenu is ShopMenu == false && Game1.activeClickableMenu is IClickableMenu == false) { scale *= 0.5f; } - System.Reflection.FieldInfo matrixField = Game1.spriteBatch.GetType().GetField("_matrix", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - object originMatrix = matrixField.GetValue(Game1.spriteBatch); + System.Reflection.FieldInfo spriteEffectField = Game1.spriteBatch.GetType().GetField("_spriteEffect", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + SpriteEffect originSpriteEffect = spriteEffectField?.GetValue(Game1.spriteBatch) as SpriteEffect; + var originMatrix = originSpriteEffect?.TransformMatrix; Game1.spriteBatch.End(); - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, Microsoft.Xna.Framework.Matrix.CreateScale(1f)); + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(1f)); IClickableMenu.drawTextureBoxWithIconAndText(Game1.spriteBatch, Game1.smallFont, Game1.mouseCursors, new Rectangle(0x100, 0x100, 10, 10), null, new Rectangle(0, 0, 1, 1), - this.alias, this.buttonRectangle.X, this.buttonRectangle.Y, this.buttonRectangle.Width, this.buttonRectangle.Height, Color.BurlyWood * scale, 4f, + this.Alias, this.ButtonRectangle.X, this.ButtonRectangle.Y, this.ButtonRectangle.Width, this.ButtonRectangle.Height, Color.BurlyWood * scale, 4f, true, false, true, false, false, false, false); // Remove bold to fix the text position issue Game1.spriteBatch.End(); if(originMatrix != null) diff --git a/src/SMAPI.Mods.VirtualKeyboard/ModConfig.cs b/src/SMAPI.Mods.VirtualKeyboard/ModConfig.cs index 9168c8a5..cfcf00e9 100644 --- a/src/SMAPI.Mods.VirtualKeyboard/ModConfig.cs +++ b/src/SMAPI.Mods.VirtualKeyboard/ModConfig.cs @@ -2,18 +2,18 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard { class ModConfig { - public Toggle vToggle { get; set; } = new Toggle(new Rect(36, 12, 64, 64), true, SButton.None); + public Toggle vToggle { get; set; } = new(new Rect(36, 12, 64, 64), true, SButton.None); public VirtualButton[] buttons { get; set;} = new VirtualButton[] { - new VirtualButton(SButton.Q, new Rect(190, 80, 90, 90), 0.5f), - new VirtualButton(SButton.I, new Rect(290, 80, 90, 90), 0.5f), - new VirtualButton(SButton.O, new Rect(390, 80, 90, 90), 0.5f), - new VirtualButton(SButton.P, new Rect(490, 80, 90, 90), 0.5f) + new(SButton.Q, new Rect(190, 80, 90, 90), 0.5f), + new(SButton.I, new Rect(290, 80, 90, 90), 0.5f), + new(SButton.O, new Rect(390, 80, 90, 90), 0.5f), + new(SButton.P, new Rect(490, 80, 90, 90), 0.5f) }; public VirtualButton[] buttonsExtend { get; set; } = new VirtualButton[] { - new VirtualButton(SButton.MouseRight, new Rect(190, 170, 162, 90), 0.5f, "RightMouse"), - new VirtualButton(SButton.None, new Rect(360, 170, 92, 90), 0.5f, "Zoom", "zoom 1.0"), - new VirtualButton(SButton.RightWindows, new Rect(460, 170, 162, 90), 0.5f, "Command"), - new VirtualButton(SButton.RightControl, new Rect(630, 170, 162, 90), 0.5f, "Console") + new(SButton.MouseRight, new Rect(190, 170, 162, 90), 0.5f, "RightMouse"), + new(SButton.None, new Rect(360, 170, 92, 90), 0.5f, "Zoom", "zoom 1.0"), + new(SButton.RightWindows, new Rect(460, 170, 162, 90), 0.5f, "Command"), + new(SButton.RightControl, new Rect(630, 170, 162, 90), 0.5f, "Console") }; internal class VirtualButton { public SButton key { get;set; } diff --git a/src/SMAPI.Mods.VirtualKeyboard/Properties/AssemblyInfo.cs b/src/SMAPI.Mods.VirtualKeyboard/Properties/AssemblyInfo.cs index ae750e04..5f282702 100644 --- a/src/SMAPI.Mods.VirtualKeyboard/Properties/AssemblyInfo.cs +++ b/src/SMAPI.Mods.VirtualKeyboard/Properties/AssemblyInfo.cs @@ -1,36 +1 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("StardewModdingAPI.Mods.VirtualKeyboard")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("StardewModdingAPI.Mods.VirtualKeyboard")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("29cce9c9-6811-415d-a681-a6d47073924d")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] + \ No newline at end of file diff --git a/src/SMAPI.Mods.VirtualKeyboard/SMAPI.Mods.VirtualKeyboard.csproj b/src/SMAPI.Mods.VirtualKeyboard/SMAPI.Mods.VirtualKeyboard.csproj index 47863bce..ec57ac9d 100644 --- a/src/SMAPI.Mods.VirtualKeyboard/SMAPI.Mods.VirtualKeyboard.csproj +++ b/src/SMAPI.Mods.VirtualKeyboard/SMAPI.Mods.VirtualKeyboard.csproj @@ -1,18 +1,14 @@  - - + Debug AnyCPU - {29CCE9C9-6811-415D-A681-A6D47073924D} Library - Properties StardewModdingAPI.Mods.VirtualKeyboard VirtualKeyboard - v4.8 + net5.0 512 true - true @@ -32,54 +28,16 @@ 4 - - ..\..\..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\Mono.Android.dll - - + False - ..\..\..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\MonoGame.Framework.dll + ..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\MonoGame.Framework.dll - ..\SMAPI\bin\Release\StardewModdingAPI.dll + ..\SMAPI\bin\Debug\StardewModdingAPI.dll - ..\..\..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\StardewValley.dll + ..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\StardewValley.dll - - True - - - True - - - True - - - True - - - True - - - True - - - - True - - - True - - - True - - - - - - - - @@ -93,5 +51,4 @@ SMAPI.Toolkit - \ No newline at end of file diff --git a/src/SMAPI.Mods.VirtualKeyboard/VirtualToggle.cs b/src/SMAPI.Mods.VirtualKeyboard/VirtualToggle.cs index ee147152..b2dac742 100644 --- a/src/SMAPI.Mods.VirtualKeyboard/VirtualToggle.cs +++ b/src/SMAPI.Mods.VirtualKeyboard/VirtualToggle.cs @@ -10,105 +10,105 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard { class VirtualToggle { - private readonly IModHelper helper; + private readonly IModHelper Helper; private readonly IMonitor Monitor; - private int enabledStage = 0; - private bool autoHidden = true; - private bool isDefault = true; - private ClickableTextureComponent virtualToggleButton; + private int EnabledStage = 0; + private bool AutoHidden = true; + private bool IsDefault = true; + private ClickableTextureComponent VirtualToggleButton; - private List keyboard = new List(); - private List keyboardExtend = new List(); - private ModConfig modConfig; - private Texture2D texture; - private int lastPressTick = 0; + private List Keyboard = new(); + private List KeyboardExtend = new(); + private ModConfig ModConfig; + private Texture2D Texture; + private int LastPressTick = 0; public VirtualToggle(IModHelper helper, IMonitor monitor) { this.Monitor = monitor; - this.helper = helper; - this.texture = this.helper.Content.Load("assets/togglebutton.png", ContentSource.ModFolder); + this.Helper = helper; + this.Texture = this.Helper.ModContent.Load("assets/togglebutton.png"); - this.modConfig = helper.ReadConfig(); - for (int i = 0; i < this.modConfig.buttons.Length; i++) - this.keyboard.Add(new KeyButton(helper, this.modConfig.buttons[i], this.Monitor)); - for (int i = 0; i < this.modConfig.buttonsExtend.Length; i++) - this.keyboardExtend.Add(new KeyButton(helper, this.modConfig.buttonsExtend[i], this.Monitor)); + this.ModConfig = helper.ReadConfig(); + for (int i = 0; i < this.ModConfig.buttons.Length; i++) + this.Keyboard.Add(new KeyButton(helper, this.ModConfig.buttons[i], this.Monitor)); + for (int i = 0; i < this.ModConfig.buttonsExtend.Length; i++) + this.KeyboardExtend.Add(new KeyButton(helper, this.ModConfig.buttonsExtend[i], this.Monitor)); - if (this.modConfig.vToggle.rectangle.X != 36 || this.modConfig.vToggle.rectangle.Y != 12) - this.isDefault = false; - this.autoHidden = this.modConfig.vToggle.autoHidden; + if (this.ModConfig.vToggle.rectangle.X != 36 || this.ModConfig.vToggle.rectangle.Y != 12) + this.IsDefault = false; + this.AutoHidden = this.ModConfig.vToggle.autoHidden; - this.virtualToggleButton = new ClickableTextureComponent(new Rectangle(Game1.toolbarPaddingX + 64, 12, 128, 128), this.texture, new Rectangle(0, 0, 16, 16), 5.75f, false); - helper.WriteConfig(this.modConfig); + this.VirtualToggleButton = new ClickableTextureComponent(new Rectangle(Game1.toolbarPaddingX + 64, 12, 128, 128), this.Texture, new Rectangle(0, 0, 16, 16), 5.75f, false); + helper.WriteConfig(this.ModConfig); - this.helper.Events.Display.Rendered += this.OnRendered; - this.helper.Events.Display.MenuChanged += this.OnMenuChanged; - this.helper.Events.Input.ButtonPressed += this.VirtualToggleButtonPressed; + this.Helper.Events.Display.Rendered += this.OnRendered; + this.Helper.Events.Display.MenuChanged += this.OnMenuChanged; + this.Helper.Events.Input.ButtonPressed += this.VirtualToggleButtonPressed; } private void OnMenuChanged(object sender, MenuChangedEventArgs e) { - if(this.autoHidden && e.NewMenu != null) { - foreach (var keys in this.keyboard) + if(this.AutoHidden && e.NewMenu != null) { + foreach (var keys in this.Keyboard) { - keys.hidden = true; + keys.Hidden = true; } - foreach (var keys in this.keyboardExtend) + foreach (var keys in this.KeyboardExtend) { - keys.hidden = true; + keys.Hidden = true; } - this.enabledStage = 0; + this.EnabledStage = 0; } } private void VirtualToggleButtonPressed(object sender, ButtonPressedEventArgs e) { Vector2 screenPixels = e.Cursor.ScreenPixels; - if (this.modConfig.vToggle.key != SButton.None && e.Button == this.modConfig.vToggle.key) - this.toggleLogic(); - else if (e.Button == SButton.MouseLeft && this.shouldTrigger(screenPixels)) - this.toggleLogic(); + if (this.ModConfig.vToggle.key != SButton.None && e.Button == this.ModConfig.vToggle.key) + this.ToggleLogic(); + else if (e.Button == SButton.MouseLeft && this.ShouldTrigger(screenPixels)) + this.ToggleLogic(); } - private void toggleLogic() + private void ToggleLogic() { - switch (this.enabledStage) + switch (this.EnabledStage) { case 0: - foreach (var keys in this.keyboard) + foreach (var keys in this.Keyboard) { - keys.hidden = false; + keys.Hidden = false; } - foreach (var keys in this.keyboardExtend) + foreach (var keys in this.KeyboardExtend) { - keys.hidden = true; + keys.Hidden = true; } - this.enabledStage = 1; + this.EnabledStage = 1; break; - case 1 when this.keyboardExtend.Count > 0: - foreach (var keys in this.keyboardExtend) + case 1 when this.KeyboardExtend.Count > 0: + foreach (var keys in this.KeyboardExtend) { - keys.hidden = false; + keys.Hidden = false; } - this.enabledStage = 2; + this.EnabledStage = 2; break; default: - foreach (var keys in this.keyboard) + foreach (var keys in this.Keyboard) { - keys.hidden = true; + keys.Hidden = true; } - foreach (var keys in this.keyboardExtend) + foreach (var keys in this.KeyboardExtend) { - keys.hidden = true; + keys.Hidden = true; } - this.enabledStage = 0; + this.EnabledStage = 0; if (Game1.activeClickableMenu is IClickableMenu menu && !(Game1.activeClickableMenu is DialogueBox)) { menu.exitThisMenu(); @@ -119,16 +119,16 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard } } - private bool shouldTrigger(Vector2 screenPixels) + private bool ShouldTrigger(Vector2 screenPixels) { int tick = Game1.ticks; - if(tick - this.lastPressTick <= 6) + if(tick - this.LastPressTick <= 6) { return false; } - if (this.virtualToggleButton.containsPoint((int)(screenPixels.X * Game1.options.zoomLevel), (int)(screenPixels.Y * Game1.options.zoomLevel))) + if (this.VirtualToggleButton.containsPoint((int)(screenPixels.X * Game1.options.zoomLevel), (int)(screenPixels.Y * Game1.options.zoomLevel))) { - this.lastPressTick = tick; + this.LastPressTick = tick; Toolbar.toolbarPressed = true; return true; } @@ -137,42 +137,43 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard private void OnRendered(object sender, EventArgs e) { - if (this.isDefault) + if (this.IsDefault) { if (Game1.options.verticalToolbar) - this.virtualToggleButton.bounds.X = Game1.toolbarPaddingX + Game1.toolbar.itemSlotSize + 200; + this.VirtualToggleButton.bounds.X = Game1.toolbarPaddingX + Game1.toolbar.itemSlotSize + 200; else - this.virtualToggleButton.bounds.X = Game1.toolbarPaddingX + Game1.toolbar.itemSlotSize + 50; + this.VirtualToggleButton.bounds.X = Game1.toolbarPaddingX + Game1.toolbar.itemSlotSize + 50; 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; + object toolbarHeight = this.Helper.Reflection.GetField(Game1.toolbar, "toolbarHeight").GetValue(); + this.VirtualToggleButton.bounds.Y = (int)toolbarHeight + 50; } else { - this.virtualToggleButton.bounds.Y = 12; + this.VirtualToggleButton.bounds.Y = 12; } } else { - this.virtualToggleButton.bounds.X = this.modConfig.vToggle.rectangle.X; - this.virtualToggleButton.bounds.Y = this.modConfig.vToggle.rectangle.Y; + this.VirtualToggleButton.bounds.X = this.ModConfig.vToggle.rectangle.X; + this.VirtualToggleButton.bounds.Y = this.ModConfig.vToggle.rectangle.Y; } float scale = 1f; - if (this.enabledStage == 0) + if (this.EnabledStage == 0) { scale = 0.5f; } if (!Game1.eventUp && Game1.activeClickableMenu is GameMenu == false && Game1.activeClickableMenu is ShopMenu == false) scale = 0.25f; - System.Reflection.FieldInfo matrixField = Game1.spriteBatch.GetType().GetField("_matrix", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - object originMatrix = matrixField.GetValue(Game1.spriteBatch); + System.Reflection.FieldInfo spriteEffectField = Game1.spriteBatch.GetType().GetField("_spriteEffect", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + SpriteEffect originSpriteEffect = spriteEffectField?.GetValue(Game1.spriteBatch) as SpriteEffect; + var originMatrix = originSpriteEffect?.TransformMatrix; Game1.spriteBatch.End(); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, Microsoft.Xna.Framework.Matrix.CreateScale(1f)); - this.virtualToggleButton.draw(Game1.spriteBatch, Color.White * scale, 0.000001f); + this.VirtualToggleButton.draw(Game1.spriteBatch, Color.White * scale, 0.000001f); Game1.spriteBatch.End(); if (originMatrix != null) { diff --git a/src/SMAPI.Mods.VirtualKeyboard/manifest.json b/src/SMAPI.Mods.VirtualKeyboard/manifest.json index d70db90d..d8c4809f 100644 --- a/src/SMAPI.Mods.VirtualKeyboard/manifest.json +++ b/src/SMAPI.Mods.VirtualKeyboard/manifest.json @@ -1,8 +1,8 @@ { "Name": "VirtualKeyboard", "Author": "SMAPI", - "Version": "3.3.1", - "MinimumApiVersion": "3.4.0", + "Version": "4.0.1", + "MinimumApiVersion": "3.18.2", "Description": "A much needed Virtual Keyboard for SMAPI Android.", "UniqueID": "VirtualKeyboard", "EntryDll": "VirtualKeyboard.dll", diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceMethods.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceMethods.cs index 6130d0b2..1b7b57b5 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceMethods.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceMethods.cs @@ -16,11 +16,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades HarmonyMethod finalizer = null) { if (Constants.HarmonyEnabled) -#if HARMONY_2 return instance.Patch(original, prefix, postfix, transpiler, finalizer); -#else - return instance.Patch(original, prefix, postfix, transpiler); -#endif else return null; } diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/ModuleReferenceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/ModuleReferenceRewriter.cs new file mode 100644 index 00000000..ed69b734 --- /dev/null +++ b/src/SMAPI/Framework/ModLoading/Rewriters/ModuleReferenceRewriter.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace StardewModdingAPI.Framework.ModLoading.Rewriters +{ + /// Rewrites all references to a type. + internal class ModuleReferenceRewriter : IInstructionHandler + { + /********* + ** Accessors + *********/ + /// + public string DefaultPhrase { get; } + + /// + public ISet Flags { get; } = new HashSet(); + + /// + public ISet Phrases { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); + + private readonly string AssemblyName; + + private readonly AssemblyNameReference Target; + + + public ModuleReferenceRewriter(string phrase, string assemblyName, Assembly target) + { + this.DefaultPhrase = $"{phrase} assembly ref"; + this.AssemblyName = assemblyName; + this.Target = AssemblyNameReference.Parse(target.FullName); + } + + public bool Handle(ModuleDefinition module) + { + if (!module.AssemblyReferences.Any(assembly => assembly.Name.Equals(this.AssemblyName))) + { + return false; + } + // add target assembly references + module.AssemblyReferences.Add(this.Target); + + // rewrite type scopes to use target assemblies + IEnumerable typeReferences = module.GetTypeReferences() + .Where(p => p.Scope.Name.Equals(this.AssemblyName)) + .OrderBy(p => p.FullName); + foreach (TypeReference type in typeReferences) + type.Scope = this.Target; + + // rewrite types using custom attributes + foreach (TypeDefinition type in module.GetTypes()) + { + foreach (CustomAttribute attr in type.CustomAttributes) + { + foreach (CustomAttributeArgument conField in attr.ConstructorArguments) + { + if (conField.Value is TypeReference typeRef) + typeRef.Scope = this.Target; + } + } + } + + for (int i = module.AssemblyReferences.Count - 1; i >= 0; i--) + { + if(module.AssemblyReferences[i].Name.Equals(this.AssemblyName)) + { + module.AssemblyReferences.RemoveAt(i); + } + } + + this.Flags.Add(InstructionHandleResult.Rewritten); + + return true; + } + + public bool Handle(ModuleDefinition module, TypeReference type, Action replaceWith) + { + return false; + } + + public bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) + { + return false; + } + } +} diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 0a5e501f..f1bd6a2d 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -53,59 +53,47 @@ namespace StardewModdingAPI.Metadata yield return new FieldReplaceRewriter() .AddField(typeof(DecoratableLocation), "furniture", typeof(GameLocation), nameof(GameLocation.furniture)) .AddField(typeof(Farm), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps)) -#if SMAPI_FOR_MOBILE - .AddField(typeof(ItemGrabMenu), "context", typeof(ItemGrabMenu), "specialObject") -#endif .AddField(typeof(MineShaft), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps)); #if SMAPI_FOR_MOBILE -#if SMAPI_LEGACY_PATCH - // Redirect reference - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isRaining", nameof(Game1Methods.IsRainingProp)); -#if !ANDROID_TARGET_MOBILE_LEGACY - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isSnowing", nameof(Game1Methods.IsSnowingProp)); -#endif - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isDebrisWeather", nameof(Game1Methods.IsDebrisWeatherProp)); - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "rainDrops", nameof(Game1Methods.RainDropsProp)); + // module rewrite for .Net 5 runtime assemblies + yield return new ModuleReferenceRewriter("System.Collections", "System.Collections", typeof(System.Collections.CollectionBase).Assembly); + yield return new ModuleReferenceRewriter("System.Runtime", "System.Runtime", typeof(System.Collections.CollectionBase).Assembly); - // yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(WeatherDebrisManager), "debrisWeather","weatherDebrisList", "Instance"); -#endif - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "onScreenMenus", "onScreenMenus"); - yield return new PropertyToFieldRewriter(typeof(Game1), "toolSpriteSheet", "toolSpriteSheet"); - // yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(GameLocation), typeof(DebrisManager), "debris", this.Monitor, "debrisNetCollection"); + yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "onScreenMenus", "onScreenMenus"); - // Menu fix - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods), "trashCan", nameof(MenuWithInventoryMethods.TrashCanProp)); - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods), "fillStacksButton", nameof(ItemGrabMenuMethods.FillStacksButtonProp)); - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(AnimalQueryMenu), typeof(AnimalQueryMenuMethods), "allowReproductionButton", nameof(AnimalQueryMenuMethods.AllowReproductionButtonProp)); - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(AnimalQueryMenu), typeof(AnimalQueryMenuMethods), "sellButton", nameof(AnimalQueryMenuMethods.SellButtonProp)); - yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(AnimalQueryMenu), typeof(AnimalQueryMenuMethods), "moveHomeButton", nameof(AnimalQueryMenuMethods.MoveHomeButtonProp)); - // TextBox fix - yield return new TypePropertyToAnotherTypeMethodRewriter(typeof(TextBox), typeof(TextBoxMethods), "Selected", null, "SelectedSetter"); + // Menu fix + yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods), "trashCan", nameof(MenuWithInventoryMethods.TrashCanProp)); + yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods), "fillStacksButton", nameof(ItemGrabMenuMethods.FillStacksButtonProp)); + yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(AnimalQueryMenu), typeof(AnimalQueryMenuMethods), "allowReproductionButton", nameof(AnimalQueryMenuMethods.AllowReproductionButtonProp)); + yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(AnimalQueryMenu), typeof(AnimalQueryMenuMethods), "sellButton", nameof(AnimalQueryMenuMethods.SellButtonProp)); + yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(AnimalQueryMenu), typeof(AnimalQueryMenuMethods), "moveHomeButton", nameof(AnimalQueryMenuMethods.MoveHomeButtonProp)); + // TextBox fix + yield return new TypePropertyToAnotherTypeMethodRewriter(typeof(TextBox), typeof(TextBoxMethods), "Selected", null, "SelectedSetter"); - // Rewrite Missing Type - yield return new TypeReferenceRewriter("StardewValley.Menus.CraftingPage", typeof(CraftingPageMobile)); - yield return new TypeReferenceRewriter("StardewValley.Menus.InventoryMenu/BorderSide", typeof(InventoryMenuMethods.BorderSide)); + // Rewrite Missing Type + yield return new TypeReferenceRewriter("StardewValley.Menus.CraftingPage", typeof(CraftingPageMobile)); + yield return new TypeReferenceRewriter("StardewValley.Menus.InventoryMenu/BorderSide", typeof(InventoryMenuMethods.BorderSide)); - //Method Rewrites - yield return new MethodParentRewriter(typeof(Game1), typeof(Game1Methods)); - yield return new MethodParentRewriter(typeof(IClickableMenu), typeof(IClickableMenuMethods)); - yield return new MethodParentRewriter(typeof(SpriteText), typeof(SpriteTextMethods)); - yield return new MethodParentRewriter(typeof(Utility), typeof(UtilityMethods)); + //Method Rewrites + yield return new MethodParentRewriter(typeof(Game1), typeof(Game1Methods)); + yield return new MethodParentRewriter(typeof(IClickableMenu), typeof(IClickableMenuMethods)); + yield return new MethodParentRewriter(typeof(SpriteText), typeof(SpriteTextMethods)); + yield return new MethodParentRewriter(typeof(Utility), typeof(UtilityMethods)); - //Constructor Rewrites - yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods)); - yield return new MethodParentRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods)); - 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)); + //Constructor Rewrites + yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods)); + yield return new MethodParentRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods)); + 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)); #endif - // heuristic rewrites - yield return new HeuristicFieldRewriter(this.ValidateReferencesToAssemblies); - yield return new HeuristicMethodRewriter(this.ValidateReferencesToAssemblies); + // heuristic rewrites + yield return new HeuristicFieldRewriter(this.ValidateReferencesToAssemblies); + yield return new HeuristicMethodRewriter(this.ValidateReferencesToAssemblies); #if SMAPI_FOR_MOBILE yield return new HeuristicFieldAccessibilityRewriter(this.ValidateReferencesToAssemblies); #endif @@ -124,16 +112,16 @@ namespace StardewModdingAPI.Metadata #endif #if SMAPI_FOR_MOBILE - // MonoMod fix - if (!Constants.HarmonyEnabled) - { - yield return new MethodToAnotherStaticMethodRewriter(typeof(Harmony), (method) => method.Name == "Patch", typeof(HarmonyInstanceMethods), "Patch"); - yield return new MethodToAnotherStaticMethodRewriter(typeof(Harmony), (method) => method.Name == "PatchAll" && method.Parameters.Count == 0, typeof(HarmonyInstanceMethods), "PatchAll"); - yield return new MethodToAnotherStaticMethodRewriter(typeof(Harmony), (method) => method.Name == "PatchAll" && method.Parameters.Count == 1, typeof(HarmonyInstanceMethods), "PatchAllToAssembly"); - } + // MonoMod fix + if (!Constants.HarmonyEnabled) + { + yield return new MethodToAnotherStaticMethodRewriter(typeof(Harmony), (method) => method.Name == "Patch", typeof(HarmonyInstanceMethods), "Patch"); + yield return new MethodToAnotherStaticMethodRewriter(typeof(Harmony), (method) => method.Name == "PatchAll" && method.Parameters.Count == 0, typeof(HarmonyInstanceMethods), "PatchAll"); + yield return new MethodToAnotherStaticMethodRewriter(typeof(Harmony), (method) => method.Name == "PatchAll" && method.Parameters.Count == 1, typeof(HarmonyInstanceMethods), "PatchAllToAssembly"); + } - if(Constants.RewriteMissing) - yield return new ReferenceToMissingMemberRewriter(this.ValidateReferencesToAssemblies); + if(Constants.RewriteMissing) + yield return new ReferenceToMissingMemberRewriter(this.ValidateReferencesToAssemblies); #endif } else diff --git a/src/SMAPI/Properties/AssemblyInfo.cs b/src/SMAPI/Properties/AssemblyInfo.cs index afff16b8..20a0469d 100644 --- a/src/SMAPI/Properties/AssemblyInfo.cs +++ b/src/SMAPI/Properties/AssemblyInfo.cs @@ -4,3 +4,7 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // Moq for unit testing [assembly: InternalsVisibleTo("ContentPatcher")] [assembly: InternalsVisibleTo("ErrorHandler")] +#if SMAPI_FOR_MOBILE +[assembly: InternalsVisibleTo("VirtualKeyboard")] +#endif +