Virtual Keyboard Mod + Updated SMainActivity, Some external Assembly references

This commit is contained in:
Chris 2019-05-30 10:52:47 -04:00
parent 6c33ddacd9
commit 1b6361b32d
21 changed files with 751 additions and 121 deletions

View File

@ -73,6 +73,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEM
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI", "StardewModdingAPI\StardewModdingAPI.csproj", "{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI", "StardewModdingAPI\StardewModdingAPI.csproj", "{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI.Mods.VirtualKeyboard", "StardewModdingAPI.Mods.VirtualKeyboard\StardewModdingAPI.Mods.VirtualKeyboard.csproj", "{29CCE9C9-6811-415D-A681-A6D47073924D}"
EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution GlobalSection(SharedMSBuildProjectFiles) = preSolution
SMAPI.Internal\SMAPI.Internal.projitems*{443ddf81-6aaf-420a-a610-3459f37e5575}*SharedItemsImports = 4 SMAPI.Internal\SMAPI.Internal.projitems*{443ddf81-6aaf-420a-a610-3459f37e5575}*SharedItemsImports = 4
@ -129,6 +131,10 @@ Global
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{9898B56E-51EB-40CF-8B1F-ACEB4B6397A7}.Release|Any CPU.Build.0 = 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
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -0,0 +1,145 @@
using System;
using Microsoft.Xna.Framework;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Menus;
using static StardewModdingAPI.Mods.VirtualKeyboard.ModConfig;
using System.Reflection;
using Microsoft.Xna.Framework.Input;
namespace StardewModdingAPI.Mods.VirtualKeyboard
{
class KeyButton
{
private readonly IModHelper helper;
private readonly IMonitor Monitor;
private readonly Rectangle buttonRectangle;
private readonly int padding;
private readonly IReflectedMethod RaiseButtonPressed;
private readonly IReflectedMethod RaiseButtonReleased;
private readonly IReflectedMethod Legacy_KeyPressed;
private readonly IReflectedMethod Legacy_KeyReleased;
private readonly SButton button;
private readonly float transparency;
public bool hidden;
private bool raisingPressed = false;
private bool raisingReleased = false;
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.padding = buttonDefine.rectangle.Padding;
this.button = buttonDefine.key;
if (buttonDefine.transparency <= 0.01f || buttonDefine.transparency > 1f)
{
buttonDefine.transparency = 0.5f;
}
this.transparency = buttonDefine.transparency;
helper.Events.Display.RenderingHud += this.OnRenderingHud;
helper.Events.Input.ButtonReleased += this.EventInputButtonReleased;
helper.Events.Input.ButtonPressed += this.EventInputButtonPressed;
//TODO
//Use C# Reflection and re-enable SMAPI IReflected checks
MainActivity activity = this.helper.Reflection.GetField<MainActivity>(typeof(MainActivity), "instance").GetValue();
object score = activity.GetType().GetField("core", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(activity);
object eventManager = score.GetType().GetField("EventManager", BindingFlags.Public | BindingFlags.Instance).GetValue(score);
object buttonPressed = eventManager.GetType().GetField("ButtonPressed", BindingFlags.Public | BindingFlags.Instance).GetValue(eventManager);
object buttonReleased = eventManager.GetType().GetField("ButtonReleased", BindingFlags.Public | BindingFlags.Instance).GetValue(eventManager);
object legacyButtonPressed = eventManager.GetType().GetField("Legacy_KeyPressed", BindingFlags.Public | BindingFlags.Instance).GetValue(eventManager);
object legacyButtonReleased = eventManager.GetType().GetField("Legacy_KeyReleased", BindingFlags.Public | BindingFlags.Instance).GetValue(eventManager);
this.RaiseButtonPressed = this.helper.Reflection.GetMethod(buttonPressed, "Raise");
this.RaiseButtonReleased = this.helper.Reflection.GetMethod(buttonReleased, "Raise");
this.Legacy_KeyPressed = this.helper.Reflection.GetMethod(legacyButtonPressed, "Raise");
this.Legacy_KeyReleased = this.helper.Reflection.GetMethod(legacyButtonReleased, "Raise");
}
private bool shouldTrigger(Vector2 point)
{
int x1 = Mouse.GetState().X / (int)Game1.NativeZoomLevel;
int y1 = Mouse.GetState().Y / (int)Game1.NativeZoomLevel;
if (this.buttonRectangle.Contains(x1, y1))
{
return true;
}
return false;
}
private void EventInputButtonPressed(object sender, ButtonPressedEventArgs e)
{
if (this.raisingPressed)
{
return;
}
Vector2 point = e.Cursor.ScreenPixels;
if (this.shouldTrigger(point))
{
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);
try
{
this.raisingPressed = true;
//METHODBASE.INVOKE Method
//this.RaiseButtonPressed.Invoke("What goes here???", new object[] { buttonPressedEventArgs });
this.RaiseButtonPressed.Invoke(new object[] { buttonPressedEventArgs });
this.Legacy_KeyPressed.Invoke(new object[] { eventArgsKey });
}
finally
{
this.raisingPressed = false;
}
}
}
private void EventInputButtonReleased(object sender, ButtonReleasedEventArgs e)
{
if (this.raisingReleased)
{
return;
}
Vector2 point = e.Cursor.ScreenPixels;
if (this.shouldTrigger(point))
{
object inputState = this.helper.Reflection.GetField<object>(e, "InputState").GetValue();
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);
try
{
this.raisingReleased = true;
this.RaiseButtonReleased.Invoke(new object[] { buttonReleasedEventArgs });
this.Legacy_KeyReleased.Invoke(new object[] { eventArgsKeyReleased });
}
finally
{
this.raisingReleased = false;
}
}
}
/// <summary>Raised before drawing the HUD (item toolbar, clock, etc) to the screen.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void OnRenderingHud(object sender, EventArgs e)
{
if (!Game1.eventUp && !this.hidden)
{
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);
}
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StardewValley;
namespace StardewModdingAPI.Mods.VirtualKeyboard
{
class ModConfig
{
public VirtualButton[] buttons { get; set; } = new VirtualButton[] {
new VirtualButton(SButton.Q, new Rect(192, 125, 90, 90, 6), 0.5f),
new VirtualButton(SButton.I, new Rect(288, 125, 90, 90, 6), 0.5f),
new VirtualButton(SButton.O, new Rect(384, 125, 90, 90, 6), 0.5f),
new VirtualButton(SButton.P, new Rect(480, 125, 90, 90, 6), 0.5f)
};
internal class VirtualButton
{
public SButton key;
public Rect rectangle;
public float transparency;
public VirtualButton(SButton key, Rect rectangle, float transparency)
{
this.key = key;
this.rectangle = rectangle;
this.transparency = transparency;
}
}
internal class Rect
{
public int X;
public int Y;
public int Width;
public int Height;
public int Padding;
public Rect(int x, int y, int width, int height, int padding)
{
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
this.Padding = padding;
}
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using StardewModdingAPI;
using StardewValley;
using StardewValley.Tools;
namespace StardewModdingAPI.Mods.VirtualKeyboard
{
public class ModEntry : Mod
{
//private List<KeyButton> keyboard = new List<KeyButton>();
//private ModConfig modConfig;
public override void Entry(IModHelper helper)
{
VirtualToggle virtualToggle = new VirtualToggle(helper, 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));
//}
//helper.WriteConfig(this.modConfig);
}
}
}

View File

@ -0,0 +1,36 @@
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

@ -0,0 +1,94 @@
<?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')" />
<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.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\Downloads\Stardew-Valley-v1-25_mod\unknown\assemblies\Mono.Android.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework">
<HintPath>..\..\..\..\..\Downloads\Stardew-Valley-v1-25_mod\unknown\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="StardewValley">
<HintPath>..\..\..\..\..\Downloads\Stardew-Valley-v1-25_mod\unknown\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>
<ProjectReference Include="..\StardewModdingAPI\StardewModdingAPI.csproj">
<Project>{9898b56e-51eb-40cf-8b1f-aceb4b6397a7}</Project>
<Name>StardewModdingAPI</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="manifest.json" />
</ItemGroup>
<ItemGroup>
<Content Include="assets\togglebutton.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
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
{
class VirtualToggle
{
private readonly IModHelper helper;
private readonly IMonitor Monitor;
private bool enabled = false;
private ClickableTextureComponent virtualToggleButton;
private List<KeyButton> keyboard = new List<KeyButton>();
private ModConfig modConfig;
private Texture2D texture;
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.virtualToggleButton = new ClickableTextureComponent(new Rectangle(Game1.toolbarPaddingX + 36, 12, 64, 64), this.texture, new Rectangle(0, 0, 16, 16), 5.75f, false);
this.modConfig = helper.ReadConfig<ModConfig>();
for (int i = 0; i < this.modConfig.buttons.Length; i++)
{
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;
}
private void VirtualToggleButtonPressed(object sender, ButtonPressedEventArgs e)
{
if (!this.enabled && this.shouldTrigger())
{
this.enabled = true;
foreach (var keys in this.keyboard)
{
keys.hidden = false;
}
}
else if (this.enabled && this.shouldTrigger())
{
this.enabled = false;
foreach (var keys in this.keyboard)
{
keys.hidden = true;
}
}
}
private bool shouldTrigger()
{
int x1 = Mouse.GetState().X / (int)Game1.NativeZoomLevel;
int y1 = Mouse.GetState().Y / (int)Game1.NativeZoomLevel;
if (this.virtualToggleButton.containsPoint(x1, y1))
{
return true;
}
return false;
}
private void VirtualToggleButtonReleased(object sender, ButtonReleasedEventArgs e)
{
}
private void OnRenderingHUD(object sender, EventArgs e)
{
if (Game1.options.verticalToolbar)
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;
float scale = 1f;
if (!this.enabled)
{
scale = 0.5f;
}
if(!Game1.eventUp)
this.virtualToggleButton.draw(Game1.spriteBatch, Color.White * scale, 0f);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

View File

@ -0,0 +1,10 @@
{
"Name": "VirtualKeyboard",
"Author": "MartyrPher",
"Version": "1.0.0",
"MinimumApiVersion": "2.10.1",
"Description": "A much needed Virtual Keyboard for SMAPI Android.",
"UniqueID": "VirtualKeyboard",
"EntryDll": "VirtualKeyboard.dll",
"UpdateKeys": [ "Nexus: null" ]
}

View File

@ -166,7 +166,11 @@ namespace StardewModdingAPI
targetAssemblies = new[] targetAssemblies = new[]
{ {
typeof(StardewValley.Game1).Assembly, // note: includes Netcode types on Linux/Mac typeof(StardewValley.Game1).Assembly, // note: includes Netcode types on Linux/Mac
typeof(Microsoft.Xna.Framework.Vector2).Assembly typeof(Microsoft.Xna.Framework.Vector2).Assembly,
typeof(MonoMod.RuntimeDetour.HarmonyDetourBridge).Assembly,
typeof(MonoMod.Utils.Platform).Assembly,
typeof(Harmony.HarmonyPatch).Assembly,
typeof(Mono.Cecil.MethodDefinition).Assembly,
}; };
break; break;

View File

@ -39,9 +39,10 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="required">Whether to throw an exception if the field is not found.</param> /// <param name="required">Whether to throw an exception if the field is not found.</param>
public IReflectedField<TValue> GetField<TValue>(object obj, string name, bool required = true) public IReflectedField<TValue> GetField<TValue>(object obj, string name, bool required = true)
{ {
return this.AssertAccessAllowed( //return this.AssertAccessAllowed(
this.Reflector.GetField<TValue>(obj, name, required) // this.Reflector.GetField<TValue>(obj, name, required)
); //);
return this.Reflector.GetField<TValue>(obj, name, required);
} }
/// <summary>Get a static field.</summary> /// <summary>Get a static field.</summary>
@ -51,9 +52,10 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="required">Whether to throw an exception if the field is not found.</param> /// <param name="required">Whether to throw an exception if the field is not found.</param>
public IReflectedField<TValue> GetField<TValue>(Type type, string name, bool required = true) public IReflectedField<TValue> GetField<TValue>(Type type, string name, bool required = true)
{ {
return this.AssertAccessAllowed( //return this.AssertAccessAllowed(
this.Reflector.GetField<TValue>(type, name, required) // this.Reflector.GetField<TValue>(type, name, required)
); //);
return this.Reflector.GetField<TValue>(type, name, required);
} }
/// <summary>Get an instance property.</summary> /// <summary>Get an instance property.</summary>
@ -86,9 +88,10 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="required">Whether to throw an exception if the field is not found.</param> /// <param name="required">Whether to throw an exception if the field is not found.</param>
public IReflectedMethod GetMethod(object obj, string name, bool required = true) public IReflectedMethod GetMethod(object obj, string name, bool required = true)
{ {
return this.AssertAccessAllowed( //return this.AssertAccessAllowed(
this.Reflector.GetMethod(obj, name, required) // this.Reflector.GetMethod(obj, name, required)
); //);
return this.Reflector.GetMethod(obj, name, required);
} }
/// <summary>Get a static method.</summary> /// <summary>Get a static method.</summary>
@ -97,9 +100,10 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="required">Whether to throw an exception if the field is not found.</param> /// <param name="required">Whether to throw an exception if the field is not found.</param>
public IReflectedMethod GetMethod(Type type, string name, bool required = true) public IReflectedMethod GetMethod(Type type, string name, bool required = true)
{ {
return this.AssertAccessAllowed( //return this.AssertAccessAllowed(
this.Reflector.GetMethod(type, name, required) // this.Reflector.GetMethod(type, name, required)
); //);
return this.Reflector.GetMethod(type, name, required);
} }

View File

@ -281,7 +281,7 @@ namespace StardewModdingAPI.Framework.ModLoading
// find (and optionally rewrite) incompatible instructions // find (and optionally rewrite) incompatible instructions
bool anyRewritten = false; bool anyRewritten = false;
IInstructionHandler[] handlers = new InstructionMetadata().GetHandlers(this.ParanoidMode).ToArray(); IInstructionHandler[] handlers = new InstructionMetadata(this.Monitor).GetHandlers(this.ParanoidMode).ToArray();
foreach (MethodDefinition method in this.GetMethods(module)) foreach (MethodDefinition method in this.GetMethods(module))
{ {
// check method definition // check method definition

View File

@ -16,6 +16,9 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <summary>The type whose field to which references should be rewritten to.</summary> /// <summary>The type whose field to which references should be rewritten to.</summary>
private readonly Type ToType; private readonly Type ToType;
/// <summary>The field name.</summary>
private readonly string FieldName;
/// <summary>The property name.</summary> /// <summary>The property name.</summary>
private readonly string PropertyName; private readonly string PropertyName;
@ -28,12 +31,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <param name="type">The type whose field to which references should be rewritten.</param> /// <param name="type">The type whose field to which references should be rewritten.</param>
/// <param name="fieldName">The field name to rewrite.</param> /// <param name="fieldName">The field name to rewrite.</param>
/// <param name="propertyName">The property name (if different).</param> /// <param name="propertyName">The property name (if different).</param>
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, string propertyName) public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, string propertyName, IMonitor monitor)
: base(type.FullName, fieldName, InstructionHandleResult.None) : base(type.FullName, fieldName, InstructionHandleResult.None)
{ {
//this.Monitor = monitor; this.Monitor = monitor;
this.Type = type; this.Type = type;
this.ToType = toType; this.ToType = toType;
this.FieldName = fieldName;
this.PropertyName = propertyName; this.PropertyName = propertyName;
} }
@ -41,7 +45,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
/// <param name="type">The type whose field to which references should be rewritten.</param> /// <param name="type">The type whose field to which references should be rewritten.</param>
/// <param name="fieldName">The field name to rewrite.</param> /// <param name="fieldName">The field name to rewrite.</param>
public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, IMonitor monitor) public TypeFieldToAnotherTypeFieldRewriter(Type type, Type toType, string fieldName, IMonitor monitor)
: this(type, toType, fieldName, fieldName) { } : this(type, toType, fieldName, fieldName, monitor) { }
/// <summary>Perform the predefined logic for an instruction if applicable.</summary> /// <summary>Perform the predefined logic for an instruction if applicable.</summary>
/// <param name="module">The assembly module containing the instruction.</param> /// <param name="module">The assembly module containing the instruction.</param>
@ -54,23 +58,21 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
if (!this.IsMatch(instruction)) if (!this.IsMatch(instruction))
return InstructionHandleResult.None; return InstructionHandleResult.None;
//Instruction: IL_0025: ldsfld StardewValley.GameLocation StardewValley.Game1::currentLocation
string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get" : "set"; string methodPrefix = instruction.OpCode == OpCodes.Ldsfld || instruction.OpCode == OpCodes.Ldfld ? "get" : "set";
try try
{ {
//MethodReference propertyRef = module.ImportReference(this.ToType.GetMethod($"{methodPrefix}_{this.PropertyName}"));
MethodReference method = module.ImportReference(this.ToType.GetMethod($"{methodPrefix}_{this.PropertyName}")); MethodReference method = module.ImportReference(this.ToType.GetMethod($"{methodPrefix}_{this.PropertyName}"));
this.Monitor.Log("Method Ref: " + method.ToString()); 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.Replace(instruction, cil.Create(OpCodes.Call, method));
} }
catch (Exception e) catch (Exception e)
{ {
//this.Monitor.Log(e.Message); this.Monitor.Log(e.Message);
this.Monitor.Log(e.StackTrace);
} }
return InstructionHandleResult.Rewritten; return InstructionHandleResult.Rewritten;
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using Android.OS;
using Harmony; using Harmony;
using MonoMod.RuntimeDetour; using MonoMod.RuntimeDetour;
@ -28,21 +29,24 @@ namespace StardewModdingAPI.Framework.Patching
/// <param name="patches">The patches to apply.</param> /// <param name="patches">The patches to apply.</param>
public void Apply(params IHarmonyPatch[] patches) public void Apply(params IHarmonyPatch[] patches)
{ {
HarmonyDetourBridge.Init(); if(Build.VERSION.SdkInt > BuildVersionCodes.LollipopMr1)
HarmonyInstance harmony = HarmonyInstance.Create("io.smapi");
foreach (IHarmonyPatch patch in patches)
{ {
try HarmonyDetourBridge.Init();
HarmonyInstance harmony = HarmonyInstance.Create("io.smapi");
foreach (IHarmonyPatch patch in patches)
{ {
patch.Apply(harmony); try
{
patch.Apply(harmony);
}
catch (Exception ex)
{
this.Monitor.Log($"Couldn't apply runtime patch '{patch.Name}' to the game. Some SMAPI features may not work correctly. See log file for details.", LogLevel.Error);
this.Monitor.Log(ex.GetLogSummary(), LogLevel.Trace);
}
} }
catch (Exception ex) }
{
this.Monitor.Log($"Couldn't apply runtime patch '{patch.Name}' to the game. Some SMAPI features may not work correctly. See log file for details.", LogLevel.Error);
this.Monitor.Log(ex.GetLogSummary(), LogLevel.Trace);
}
}
} }
} }
} }

View File

@ -17,5 +17,11 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{ {
return base.addItemToInventoryBool(item, false); return base.addItemToInventoryBool(item, false);
} }
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new int freeSpotsInInventory()
{
return base.freeSpotsInInventory(null);
}
} }
} }

View File

@ -76,7 +76,7 @@ namespace StardewModdingAPI.Framework
private readonly ModRegistry ModRegistry = new ModRegistry(); private readonly ModRegistry ModRegistry = new ModRegistry();
/// <summary>Manages SMAPI events for mods.</summary> /// <summary>Manages SMAPI events for mods.</summary>
private readonly EventManager EventManager; public readonly EventManager EventManager;
/// <summary>Whether the game is currently running.</summary> /// <summary>Whether the game is currently running.</summary>
private bool IsGameRunning; private bool IsGameRunning;
@ -296,7 +296,7 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log("The game crashed last time you played. That can be due to bugs in the game, but if it happens repeatedly you can ask for help here: https://community.playstarbound.com/threads/108375/.", LogLevel.Error); this.Monitor.Log("The game crashed last time you played. That can be due to bugs in the game, but if it happens repeatedly you can ask for help here: https://community.playstarbound.com/threads/108375/.", LogLevel.Error);
this.Monitor.Log("If you ask for help, make sure to share your SMAPI log: https://log.smapi.io.", LogLevel.Error); this.Monitor.Log("If you ask for help, make sure to share your SMAPI log: https://log.smapi.io.", LogLevel.Error);
this.Monitor.Log("Press any key to delete the crash data and continue playing.", LogLevel.Info); this.Monitor.Log("Press any key to delete the crash data and continue playing.", LogLevel.Info);
Console.ReadKey(); //Console.ReadKey();
File.Delete(Constants.FatalCrashLog); File.Delete(Constants.FatalCrashLog);
File.Delete(Constants.FatalCrashMarker); File.Delete(Constants.FatalCrashMarker);
} }

View File

@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
namespace StardewModdingAPI namespace StardewModdingAPI
{ {

View File

@ -20,6 +20,13 @@ namespace StardewModdingAPI.Metadata
/// <remarks>The current implementation only works correctly with assemblies that should always be present.</remarks> /// <remarks>The current implementation only works correctly with assemblies that should always be present.</remarks>
private readonly string[] ValidateReferencesToAssemblies = { "StardewModdingAPI", "Stardew Valley", "StardewValley", "Netcode" }; private readonly string[] ValidateReferencesToAssemblies = { "StardewModdingAPI", "Stardew Valley", "StardewValley", "Netcode" };
private readonly IMonitor Monitor;
public InstructionMetadata(IMonitor monitor)
{
this.Monitor = monitor;
}
/********* /*********
** Public methods ** Public methods
@ -42,9 +49,12 @@ namespace StardewModdingAPI.Metadata
//Constructor Rewrites //Constructor Rewrites
yield return new MethodParentRewriter(typeof(HUDMessage), typeof(HUDMessageMethods)); yield return new MethodParentRewriter(typeof(HUDMessage), typeof(HUDMessageMethods));
yield return new MethodParentRewriter(typeof(MapPageMethods), typeof(MapPageMethods)); yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods));
yield return new MethodParentRewriter(typeof(TextBox), typeof(TextBoxMethods)); yield return new MethodParentRewriter(typeof(TextBox), typeof(TextBoxMethods));
//Field Rewriters
yield return new FieldReplaceRewriter(typeof(ItemGrabMenu), "context", "specialObject");
// rewrite for Stardew Valley 1.3 // rewrite for Stardew Valley 1.3
yield return new StaticFieldToConstantRewriter<int>(typeof(Game1), "tileSize", Game1.tileSize); yield return new StaticFieldToConstantRewriter<int>(typeof(Game1), "tileSize", Game1.tileSize);
yield return new TypeReferenceRewriter("System.Collections.Generic.IList`1<StardewValley.Menus.IClickableMenu>", typeof(List<IClickableMenu>)); yield return new TypeReferenceRewriter("System.Collections.Generic.IList`1<StardewValley.Menus.IClickableMenu>", typeof(List<IClickableMenu>));
@ -58,8 +68,8 @@ namespace StardewModdingAPI.Metadata
yield return new FieldToPropertyRewriter(typeof(Game1), "stats"); yield return new FieldToPropertyRewriter(typeof(Game1), "stats");
//isRaining and isDebrisWeather fix 50% done. //isRaining and isDebrisWeather fix 50% done.
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(RainManager), "isRaining", "Instance"); yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(RainManager), "isRaining", "Instance", this.Monitor);
yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(DebrisManager), "isDebrisWeather", "Instance"); yield return new TypeFieldToAnotherTypeFieldRewriter(typeof(Game1), typeof(WeatherDebrisManager), "isDebrisWeather", "Instance", this.Monitor);
/**** /****
** detect mod issues ** detect mod issues

View File

@ -7,6 +7,7 @@ using System.Threading;
#if SMAPI_FOR_WINDOWS #if SMAPI_FOR_WINDOWS
#endif #endif
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.ModLoading;
using StardewModdingAPI.Internal; using StardewModdingAPI.Internal;
namespace StardewModdingAPI namespace StardewModdingAPI
@ -52,7 +53,6 @@ namespace StardewModdingAPI
{ {
if (name.Name.Equals(AssemblyName.GetAssemblyName(dll.FullName).Name, StringComparison.InvariantCultureIgnoreCase)) if (name.Name.Equals(AssemblyName.GetAssemblyName(dll.FullName).Name, StringComparison.InvariantCultureIgnoreCase))
{ {
Android.Util.Log.Error("Program", $"Resolving assembly: {dll.FullName}");
return Assembly.LoadFrom(dll.FullName); return Assembly.LoadFrom(dll.FullName);
} }

View File

@ -25,6 +25,7 @@ using System.Threading.Tasks;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewValley; using StardewValley;
using Android.Widget; using Android.Widget;
using StardewModdingAPI.Framework.ModLoading;
namespace StardewModdingAPI namespace StardewModdingAPI
{ {
@ -130,11 +131,14 @@ namespace StardewModdingAPI
{ {
get get
{ {
if (ContextCompat.CheckSelfPermission(this, "android.permission.ACCESS_NETWORK_STATE") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "android.permission.ACCESS_NETWORK_STATE") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "android.permission.ACCESS_WIFI_STATE") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "android.permission.INTERNET") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "android.permission.READ_EXTERNAL_STORAGE") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "android.permission.VIBRATE") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "android.permission.WAKE_LOCK") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") == Permission.Granted && ContextCompat.CheckSelfPermission(this, "com.android.vending.CHECK_LICENSE") == Permission.Granted) 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
return true; && this.PackageManager.CheckPermission("android.permission.INTERNET", this.PackageName) == Permission.Granted
} && this.PackageManager.CheckPermission("android.permission.READ_EXTERNAL_STORAGE", this.PackageName) == Permission.Granted
return false; && 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;
} }
} }
@ -530,15 +534,199 @@ namespace StardewModdingAPI
public void PromptForPermissionsIfNecessary(Action callback = null) public void PromptForPermissionsIfNecessary(Action callback = null)
{ {
//Log.It("MainActivity.PromptForPermissionsIfNecessary...");
if (this.HasPermissions) if (this.HasPermissions)
{ {
callback?.Invoke(); if (callback != null)
return; {
//Log.It("MainActivity.PromptForPermissionsIfNecessary has permissions, calling callback");
callback();
return;
}
}
else
{
//Log.It("MainActivity.PromptForPermissionsIfNecessary doesn't have permissions, prompt for them");
this._callback = callback;
this.PromptForPermissionsWithReasonFirst();
} }
this._callback = callback;
this.PromptForPermissions();
} }
private void PromptForPermissionsWithReasonFirst()
{
//Log.It("MainActivity.PromptForPermissionsWithReasonFirst...");
if (!this.HasPermissions)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
string languageCode = Locale.Default.Language.Substring(0, 2);
builder.SetMessage(this.PermissionMessageA(languageCode));
builder.SetPositiveButton(this.GetOKString(languageCode), delegate (object senderAlert, DialogClickEventArgs args)
{
//Log.It("MainActivity.PromptForPermissionsWithReasonFirst PromptForPermissions A");
this.PromptForPermissions();
});
Dialog dialog = builder.Create();
if (!this.IsFinishing)
{
dialog.Show();
return;
}
}
else
{
//Log.It("MainActivity.PromptForPermissionsWithReasonFirst PromptForPermissions B");
this.PromptForPermissions();
}
}
private string GetOKString(string languageCode)
{
if (languageCode == "de")
{
return "OK";
}
if (languageCode == "es")
{
return "DE ACUERDO";
}
if (languageCode == "ja")
{
return "OK";
}
if (languageCode == "pt")
{
return "Está bem";
}
if (languageCode == "ru")
{
return "Хорошо";
}
if (languageCode == "ko")
{
return "승인";
}
if (languageCode == "tr")
{
return "tamam";
}
if (languageCode == "fr")
{
return "D'accord";
}
if (languageCode == "hu")
{
return "rendben";
}
if (languageCode == "it")
{
return "ok";
}
if (languageCode == "zh")
{
return "好";
}
return "OK";
}
private string PermissionMessageA(string languageCode)
{
if (languageCode == "de")
{
return "Du musst die Erlaubnis zum Lesen/Schreiben auf dem externen Speicher geben, um das Spiel zu speichern und Speicherstände auf andere Plattformen übertragen zu können. Bitte gib diese Genehmigung, um spielen zu können.";
}
if (languageCode == "es")
{
return "Para guardar la partida y transferir partidas guardadas a y desde otras plataformas, se necesita permiso para leer/escribir en almacenamiento externo. Concede este permiso para poder jugar.";
}
if (languageCode == "ja")
{
return "外部機器への読み込み/書き出しの許可が、ゲームのセーブデータの保存や他プラットフォームとの双方向のデータ移行実行に必要です。プレイを続けるには許可をしてください。";
}
if (languageCode == "pt")
{
return "Para salvar o jogo e transferir jogos salvos entre plataformas é necessário permissão para ler/gravar em armazenamento externo. Forneça essa permissão para jogar.";
}
if (languageCode == "ru")
{
return "Для сохранения игры и переноса сохранений с/на другие платформы нужно разрешение на чтение-запись на внешнюю память. Дайте разрешение, чтобы начать играть.";
}
if (languageCode == "ko")
{
return "게임을 저장하려면 외부 저장공간에 대한 읽기/쓰기 권한이 필요합니다. 또한 저장 데이터 이전 기능을 허용해 다른 플랫폼에서 게임 진행상황을 가져올 때에도 권한이 필요합니다. 게임을 플레이하려면 권한을 허용해 주십시오.";
}
if (languageCode == "tr")
{
return "Oyunu kaydetmek ve kayıtları platformlardan platformlara taşımak için harici depolamada okuma/yazma izni gereklidir. Lütfen oynayabilmek için izin verin.";
}
if (languageCode == "fr")
{
return "Une autorisation de lecture / écriture sur un stockage externe est requise pour sauvegarder le jeu et vous permettre de transférer des sauvegardes vers et depuis d'autres plateformes. Veuillez donner l'autorisation afin de jouer.";
}
if (languageCode == "hu")
{
return "A játék mentéséhez, és ahhoz, hogy a különböző platformok között hordozhasd a játékmentést, engedélyezned kell a külső tárhely olvasását/írását, Kérjük, a játékhoz engedélyezd ezeket.";
}
if (languageCode == "it")
{
return "È necessaria l'autorizzazione a leggere/scrivere su un dispositivo di memorizzazione esterno per salvare la partita e per consentire di trasferire i salvataggi da e su altre piattaforme. Concedi l'autorizzazione per giocare.";
}
if (languageCode == "zh")
{
return "《星露谷物语》请求获得授权用来保存游戏数据以及访问线上功能。";
}
return "Read/write to external storage permission is required to save the game, and to allow to you transfer saves to and from other platforms. Please give permission in order to play.";
}
private string PermissionMessageB(string languageCode)
{
if (languageCode == "de")
{
return "Bitte geh in die Handy-Einstellungen > Apps > Stardew Valley > Berechtigungen und aktiviere den Speicher, um das Spiel zu spielen.";
}
if (languageCode == "es")
{
return "En el teléfono, ve a Ajustes > Aplicaciones > Stardew Valley > Permisos y activa Almacenamiento para jugar al juego.";
}
if (languageCode == "ja")
{
return "設定 > アプリ > スターデューバレー > 許可の順に開いていき、ストレージを有効にしてからゲームをプレイしましょう。";
}
if (languageCode == "pt")
{
return "Acesse Configurar > Aplicativos > Stardew Valley > Permissões e ative Armazenamento para jogar.";
}
if (languageCode == "ru")
{
return "Перейдите в меню Настройки > Приложения > Stardew Valley > Разрешения и дайте доступ к памяти, чтобы начать играть.";
}
if (languageCode == "ko")
{
return "휴대전화의 설정 > 어플리케이션 > 스타듀 밸리 > 권한 에서 저장공간을 활성화한 뒤 게임을 플레이해 주십시오.";
}
if (languageCode == "tr")
{
return "Lütfen oyunu oynayabilmek için telefonda Ayarlar > Uygulamalar > Stardew Valley > İzinler ve Depolamayı etkinleştir yapın.";
}
if (languageCode == "fr")
{
return "Veuillez aller dans les Paramètres du téléphone> Applications> Stardew Valley> Autorisations, puis activez Stockage pour jouer.";
}
if (languageCode == "hu")
{
return "Lépje be a telefonodon a Beállítások > Alkalmazások > Stardew Valley > Engedélyek menübe, majd engedélyezd a Tárhelyet a játékhoz.";
}
if (languageCode == "it")
{
return "Nel telefono, vai su Impostazioni > Applicazioni > Stardew Valley > Autorizzazioni e attiva Memoria archiviazione per giocare.";
}
if (languageCode == "zh")
{
return "可在“设置-权限隐私-按应用管理权限-星露谷物语”进行设置,并打开“电话”、“读取位置信息”、“存储”权限。";
}
return "Please go into phone Settings > Apps > Stardew Valley > Permissions, and enable Storage to play the game.";
}
private void LogPermissions() private void LogPermissions()
{ {
//("MainActivity.LogPermissions , AccessNetworkState:" + ContextCompat.CheckSelfPermission(this, "android.permission.ACCESS_NETWORK_STATE") + ", AccessWifiState:" + ContextCompat.CheckSelfPermission(this, "android.permission.ACCESS_WIFI_STATE") + ", Internet:" + ContextCompat.CheckSelfPermission(this, "android.permission.INTERNET") + ", ReadExternalStorage:" + ContextCompat.CheckSelfPermission(this, "android.permission.READ_EXTERNAL_STORAGE") + ", Vibrate:" + ContextCompat.CheckSelfPermission(this, "android.permission.VIBRATE") + ", WakeLock:" + ContextCompat.CheckSelfPermission(this, "android.permission.WAKE_LOCK") + ", WriteExternalStorage:" + ContextCompat.CheckSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") + ", CheckLicense:" + ContextCompat.CheckSelfPermission(this, "com.android.vending.CHECK_LICENSE")); //("MainActivity.LogPermissions , AccessNetworkState:" + ContextCompat.CheckSelfPermission(this, "android.permission.ACCESS_NETWORK_STATE") + ", AccessWifiState:" + ContextCompat.CheckSelfPermission(this, "android.permission.ACCESS_WIFI_STATE") + ", Internet:" + ContextCompat.CheckSelfPermission(this, "android.permission.INTERNET") + ", ReadExternalStorage:" + ContextCompat.CheckSelfPermission(this, "android.permission.READ_EXTERNAL_STORAGE") + ", Vibrate:" + ContextCompat.CheckSelfPermission(this, "android.permission.VIBRATE") + ", WakeLock:" + ContextCompat.CheckSelfPermission(this, "android.permission.WAKE_LOCK") + ", WriteExternalStorage:" + ContextCompat.CheckSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") + ", CheckLicense:" + ContextCompat.CheckSelfPermission(this, "com.android.vending.CHECK_LICENSE"));
@ -551,20 +739,15 @@ namespace StardewModdingAPI
{ {
//("MainActivity.CheckAppPermissions permissions already granted."); //("MainActivity.CheckAppPermissions permissions already granted.");
this.OnCreatePartTwo(); this.OnCreatePartTwo();
return;
} }
else this.PromptForPermissionsWithReasonFirst();
{
this.PromptForPermissions();
}
} }
public void PromptForPermissions() public void PromptForPermissions()
{ {
//("MainActivity.PromptForPermissions requesting permissions..."); //("MainActivity.PromptForPermissions requesting permissions...");
if (!this.IsFinishing) ActivityCompat.RequestPermissions(this, this.deniedPermissionsArray, 0);
{
ActivityCompat.RequestPermissions(this, this.deniedPermissionsArray, 0);
}
} }
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
@ -574,62 +757,8 @@ namespace StardewModdingAPI
{ {
//("MainActivity.OnRequestPermissionsResult no permissions returned, RETURNING"); //("MainActivity.OnRequestPermissionsResult no permissions returned, RETURNING");
return; return;
} }
string text = Java.Util.Locale.Default.Language.Substring(0, 2); string languageCode = Locale.Default.Language.Substring(0, 2);
//("OnRequestPermissionsResult Language Code:" + text);
string message;
string message2;
switch (text)
{
case "de":
message = "Du musst die Erlaubnis zum Lesen/Schreiben auf dem externen Speicher geben, um das Spiel zu speichern und Speicherstände auf andere Plattformen übertragen zu können. Bitte gib diese Genehmigung, um spielen zu können.";
message2 = "Bitte geh in die Handy-Einstellungen > Apps > Stardew Valley > Berechtigungen und aktiviere den Speicher, um das Spiel zu spielen.";
break;
case "es":
message = "Para guardar la partida y transferir partidas guardadas a y desde otras plataformas, se necesita permiso para leer/escribir en almacenamiento externo. Concede este permiso para poder jugar.";
message2 = "En el teléfono, ve a Ajustes > Aplicaciones > Stardew Valley > Permisos y activa Almacenamiento para jugar al juego.";
break;
case "ja":
message = "外部機器への読み込み/書き出しの許可が、ゲ\u30fcムのセ\u30fcブデ\u30fcタの保存や他プラットフォ\u30fcムとの双方向のデ\u30fcタ移行実行に必要です。プレイを続けるには許可をしてください。";
message2 = "設定 > アプリ > スタ\u30fcデュ\u30fcバレ\u30fc > 許可の順に開いていき、ストレ\u30fcジを有効にしてからゲ\u30fcムをプレイしましょう。";
break;
case "pt":
message = "Para salvar o jogo e transferir jogos salvos entre plataformas é necessário permissão para ler/gravar em armazenamento externo. Forneça essa permissão para jogar.";
message2 = "Acesse Configurar > Aplicativos > Stardew Valley > Permissões e ative Armazenamento para jogar.";
break;
case "ru":
message = "Для сохранения игры и переноса сохранений с/на другие платформы нужно разрешение на чтение-запись на внешнюю память. Дайте разрешение, чтобы начать играть.";
message2 = "Перейдите в меню Настройки > Приложения > Stardew Valley > Разрешения и дайте доступ к памяти, чтобы начать играть.";
break;
case "ko":
message = "게임을 저장하려면 외부 저장공간에 대한 읽기/쓰기 권한이 필요합니다. 또한 저장 데이터 이전 기능을 허용해 다른 플랫폼에서 게임 진행상황을 가져올 때에도 권한이 필요합니다. 게임을 플레이하려면 권한을 허용해 주십시오.";
message2 = "휴대전화의 설정 > 어플리케이션 > 스타듀 밸리 > 권한 에서 저장공간을 활성화한 뒤 게임을 플레이해 주십시오.";
break;
case "tr":
message = "Oyunu kaydetmek ve kayıtları platformlardan platformlara taşımak için harici depolamada okuma/yazma izni gereklidir. Lütfen oynayabilmek için izin verin.";
message2 = "Lütfen oyunu oynayabilmek için telefonda Ayarlar > Uygulamalar > Stardew Valley > İzinler ve Depolamayı etkinleştir yapın.";
break;
case "fr":
message = "Une autorisation de lecture / écriture sur un stockage externe est requise pour sauvegarder le jeu et vous permettre de transférer des sauvegardes vers et depuis d'autres plateformes. Veuillez donner l'autorisation afin de jouer.";
message2 = "Veuillez aller dans les Paramètres du téléphone> Applications> Stardew Valley> Autorisations, puis activez Stockage pour jouer.";
break;
case "hu":
message = "A játék mentéséhez, és ahhoz, hogy a különböző platformok között hordozhasd a játékmentést, engedélyezned kell a külső tárhely olvasását/írását, Kérjük, a játékhoz engedélyezd ezeket.";
message2 = "Lépje be a telefonodon a Beállítások > Alkalmazások > Stardew Valley > Engedélyek menübe, majd engedélyezd a Tárhelyet a játékhoz.";
break;
case "it":
message = "È necessaria l'autorizzazione a leggere/scrivere su un dispositivo di memorizzazione esterno per salvare la partita e per consentire di trasferire i salvataggi da e su altre piattaforme. Concedi l'autorizzazione per giocare.";
message2 = "Nel telefono, vai su Impostazioni > Applicazioni > Stardew Valley > Autorizzazioni e attiva Memoria archiviazione per giocare.";
break;
case "zh":
message = "保存游戏进度,以及授权与其它平台交换游戏进度文件,都需要对外部存储器进行读 / 写的权限。要正常游戏,请授予权限。";
message2 = "请转到手机的设置 > 应用 > Stardew Valley > 权限里,启用“存储”,以正常游戏。";
break;
default:
message = "Read/write to external storage permission is required to save the game, and to allow to you transfer saves to and from other platforms. Please give permission in order to play.";
message2 = "Please go into phone Settings > Apps > Stardew Valley > Permissions, and enable Storage to play the game.";
break;
}
int num = 0; int num = 0;
if (requestCode == 0) if (requestCode == 0)
{ {
@ -646,18 +775,19 @@ namespace StardewModdingAPI
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
if (ActivityCompat.ShouldShowRequestPermissionRationale(this, permissions[i])) if (ActivityCompat.ShouldShowRequestPermissionRationale(this, permissions[i]))
{ {
builder.SetMessage(message); builder.SetMessage(this.PermissionMessageA(languageCode));
builder.SetPositiveButton("OK", delegate builder.SetPositiveButton(this.GetOKString(languageCode), delegate (object senderAlert, DialogClickEventArgs args)
{ {
//Log.It("MainActivity.OnRequestPermissionsResult PromptForPermissions D");
this.PromptForPermissions(); this.PromptForPermissions();
}); });
} }
else else
{ {
builder.SetMessage(message2); builder.SetMessage(this.PermissionMessageB(languageCode));
builder.SetPositiveButton("OK", delegate builder.SetPositiveButton(this.GetOKString(languageCode), delegate (object senderAlert, DialogClickEventArgs args)
{ {
this.FinishAffinity(); this.OpenAppSettingsOnPhone();
}); });
} }
Dialog dialog = builder.Create(); Dialog dialog = builder.Create();
@ -685,6 +815,15 @@ namespace StardewModdingAPI
} }
} }
private void OpenAppSettingsOnPhone()
{
Intent intent = new Intent();
intent.SetAction("android.settings.APPLICATION_DETAILS_SETTINGS");
Android.Net.Uri data = Android.Net.Uri.FromParts("package", this.PackageName, null);
intent.SetData(data);
this.StartActivity(intent);
}
private void CheckUsingServerManagedPolicy() private void CheckUsingServerManagedPolicy()
{ {
//("MainActivity.CheckUsingServerManagedPolicy"); //("MainActivity.CheckUsingServerManagedPolicy");

View File

@ -90,7 +90,9 @@
<HintPath>..\..\..\..\..\Downloads\Stardew-Valley-v1-25_mod\unknown\assemblies\StardewValley.dll</HintPath> <HintPath>..\..\..\..\..\Downloads\Stardew-Valley-v1-25_mod\unknown\assemblies\StardewValley.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core">
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Xamarin.Android.Support.v4"> <Reference Include="Xamarin.Android.Support.v4">