Fix Virtual Keyboard mod

This commit is contained in:
zhiyang7 2023-02-06 16:09:33 +08:00
parent 0f94f4609d
commit a406411a04
10 changed files with 269 additions and 289 deletions

View File

@ -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<MainActivity>(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<object>(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<string>(delegate (Task<string> s) {
KeyboardInput.Show("Command", "").ContinueWith(delegate (Task<string> 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<object>(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<string> commandQueue = score.GetType().GetProperty("CommandQueue", BindingFlags.Public | BindingFlags.Instance)?.GetValue(score) as ConcurrentQueue<string>;
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<string>;
commandQueue?.Enqueue(command);
}
/// <summary>Raised before drawing the HUD (item toolbar, clock, etc) to the screen.</summary>
@ -152,19 +131,20 @@ namespace StardewModdingAPI.Mods.VirtualKeyboard
/// <param name="e">The event arguments.</param>
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)

View File

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

View File

@ -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")]


View File

@ -1,18 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{29CCE9C9-6811-415D-A681-A6D47073924D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StardewModdingAPI.Mods.VirtualKeyboard</RootNamespace>
<AssemblyName>VirtualKeyboard</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFramework>net5.0</TargetFramework>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -32,54 +28,16 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android">
<HintPath>..\..\..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\Mono.Android.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework, Version=3.7.1.189, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="MonoGame.Framework">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\MonoGame.Framework.dll</HintPath>
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="StardewModdingAPI">
<HintPath>..\SMAPI\bin\Release\StardewModdingAPI.dll</HintPath>
<HintPath>..\SMAPI\bin\Debug\StardewModdingAPI.dll</HintPath>
</Reference>
<Reference Include="StardewValley">
<HintPath>..\..\..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\StardewValley.dll</HintPath>
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\StardewValley.dll</HintPath>
</Reference>
<Reference Include="System">
<Private>True</Private>
</Reference>
<Reference Include="System.Core">
<Private>True</Private>
</Reference>
<Reference Include="System.Drawing">
<Private>True</Private>
</Reference>
<Reference Include="System.Windows.Forms">
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq">
<Private>True</Private>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data">
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http">
<Private>True</Private>
</Reference>
<Reference Include="System.Xml">
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="KeyButton.cs" />
<Compile Include="ModConfig.cs" />
<Compile Include="ModEntry.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VirtualToggle.cs" />
</ItemGroup>
<ItemGroup>
<None Include="manifest.json" />
@ -93,5 +51,4 @@
<Name>SMAPI.Toolkit</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -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<KeyButton> keyboard = new List<KeyButton>();
private List<KeyButton> keyboardExtend = new List<KeyButton>();
private ModConfig modConfig;
private Texture2D texture;
private int lastPressTick = 0;
private List<KeyButton> Keyboard = new();
private List<KeyButton> 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<Texture2D>("assets/togglebutton.png", ContentSource.ModFolder);
this.Helper = helper;
this.Texture = this.Helper.ModContent.Load<Texture2D>("assets/togglebutton.png");
this.modConfig = helper.ReadConfig<ModConfig>();
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<ModConfig>();
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<int>(Game1.toolbar, "toolbarHeight").GetValue();
this.virtualToggleButton.bounds.Y = (int)toolbarHeight + 50;
object toolbarHeight = this.Helper.Reflection.GetField<int>(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)
{

View File

@ -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",

View File

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

View File

@ -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
{
/// <summary>Rewrites all references to a type.</summary>
internal class ModuleReferenceRewriter : IInstructionHandler
{
/*********
** Accessors
*********/
/// <inheritdoc />
public string DefaultPhrase { get; }
/// <inheritdoc />
public ISet<InstructionHandleResult> Flags { get; } = new HashSet<InstructionHandleResult>();
/// <inheritdoc />
public ISet<string> Phrases { get; } = new HashSet<string>(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<TypeReference> 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<TypeReference> replaceWith)
{
return false;
}
public bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction)
{
return false;
}
}
}

View File

@ -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

View File

@ -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