diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index 91e55c1c..b2640d77 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -20,7 +20,7 @@ namespace StardewModdingAPI
** Public
****/
/// SMAPI's current semantic version.
- public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.4.1.2", allowNonStandard: true);
+ public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.4.1.5", allowNonStandard: true);
/// The minimum supported version of Stardew Valley.
public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.4.5");
@@ -109,6 +109,8 @@ namespace StardewModdingAPI
/// The language code for non-translated mod assets.
internal static LocalizedContentManager.LanguageCode DefaultLanguage { get; } = LocalizedContentManager.LanguageCode.en;
+ internal static bool MonoModInit { get; set; } = true;
+
/*********
** Internal methods
diff --git a/src/SMAPI/Framework/ModLoading/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/RewriteHelper.cs
index 795d0d2c..75160088 100644
--- a/src/SMAPI/Framework/ModLoading/RewriteHelper.cs
+++ b/src/SMAPI/Framework/ModLoading/RewriteHelper.cs
@@ -91,6 +91,12 @@ namespace StardewModdingAPI.Framework.ModLoading
if (definition.Name != reference.Name)
return false;
+ // same return type
+ if(definition is MethodInfo methodDefinition)
+ {
+ if(!RewriteHelper.IsSameType(methodDefinition.ReturnType, reference.ReturnType))
+ return false;
+ }
// same arguments
ParameterInfo[] definitionParameters = definition.GetParameters();
ParameterDefinition[] referenceParameters = reference.Parameters.ToArray();
diff --git a/src/SMAPI/Framework/Patching/GamePatcher.cs b/src/SMAPI/Framework/Patching/GamePatcher.cs
index 56d6a88d..66978eb3 100644
--- a/src/SMAPI/Framework/Patching/GamePatcher.cs
+++ b/src/SMAPI/Framework/Patching/GamePatcher.cs
@@ -29,11 +29,12 @@ namespace StardewModdingAPI.Framework.Patching
/// The patches to apply.
public void Apply(params IHarmonyPatch[] patches)
{
- if (Build.VERSION.SdkInt < BuildVersionCodes.M)
- return;
- if (!HarmonyDetourBridge.Initialized)
+ if (!HarmonyDetourBridge.Initialized && Constants.MonoModInit)
{
- HarmonyDetourBridge.Init();
+ try {
+ HarmonyDetourBridge.Init();
+ }
+ catch { Constants.MonoModInit = false; }
}
HarmonyInstance harmony = HarmonyInstance.Create("io.smapi");
@@ -41,19 +42,16 @@ namespace StardewModdingAPI.Framework.Patching
{
try
{
- patch.Apply(harmony);
+ if(Constants.MonoModInit)
+ patch.Apply(harmony);
}
catch (Exception ex)
{
+ Constants.MonoModInit = false;
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);
}
}
-
- //Keeping for reference
- //if (Build.VERSION.SdkInt > BuildVersionCodes.LollipopMr1)
- //{
- //}
}
}
}
diff --git a/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs b/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs
index e83738ca..b77133bd 100644
--- a/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs
+++ b/src/SMAPI/Framework/RewriteFacades/Game1Methods.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
+using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
using StardewValley.Menus;
@@ -106,5 +107,14 @@ namespace StardewModdingAPI.Framework.RewriteFacades
}
}
}
+ public static new void createItemDebris(Item item, Vector2 origin, int direction, GameLocation location = null, int groundLevel = -1)
+ {
+ Game1.createItemDebris(item, origin, direction, location, groundLevel);
+ }
+
+ public static void changeMusicTrack(string newTrackName)
+ {
+ Game1.changeMusicTrack(newTrackName, false, MusicContext.Default);
+ }
}
}
diff --git a/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs b/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs
index d9114ae4..a48d7a96 100644
--- a/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs
+++ b/src/SMAPI/Framework/RewriteFacades/GameLocationMethods.cs
@@ -1,13 +1,12 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Netcode;
using StardewValley;
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class GameLocationMethods : GameLocation
{
+ public void playSound(string audioName)
+ {
+ base.playSound(audioName, StardewValley.Network.NetAudio.SoundContext.Default);
+ }
}
}
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 221d251f..58bd000b 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -748,7 +748,7 @@ namespace StardewModdingAPI.Framework
shopMenu.onPurchase, shopMenu.onSell, shopMenu.storeContext);
}
}
- }
+ }
/*********
** World & player events
@@ -977,7 +977,9 @@ namespace StardewModdingAPI.Framework
this.ExitGameImmediately("The game crashed when drawing, and SMAPI was unable to recover the game.");
return;
}
-
+ }
+ finally
+ {
// recover sprite batch
try
{
diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs
index e529f5f5..a05a0dd1 100644
--- a/src/SMAPI/Metadata/InstructionMetadata.cs
+++ b/src/SMAPI/Metadata/InstructionMetadata.cs
@@ -89,6 +89,7 @@ namespace StardewModdingAPI.Metadata
yield return new MethodParentRewriter(typeof(Utility), typeof(UtilityMethods));
yield return new MethodParentRewriter(typeof(DayTimeMoneyBox), typeof(DayTimeMoneyBoxMethods));
yield return new MethodParentRewriter(typeof(SaveGame), typeof(SaveGameMethods));
+ yield return new MethodParentRewriter(typeof(GameLocation), typeof(GameLocationMethods));
//Constructor Rewrites
yield return new MethodParentRewriter(typeof(HUDMessage), typeof(HUDMessageMethods));
diff --git a/src/SMAPI/SGameConsole.cs b/src/SMAPI/SGameConsole.cs
index 9e0fdc95..115662a2 100644
--- a/src/SMAPI/SGameConsole.cs
+++ b/src/SMAPI/SGameConsole.cs
@@ -17,7 +17,9 @@ namespace StardewModdingAPI
public bool isVisible;
private readonly LinkedList> consoleMessageQueue = new LinkedList>();
+ private Dictionary> parseTextCache = new Dictionary>();
private MobileScrollbox scrollbox;
+ private MobileScrollbar scrollbar;
private ClickableTextureComponent commandButton;
@@ -29,7 +31,8 @@ namespace StardewModdingAPI
private int scrollLastY = 0;
- private int MaxScrollBoxHeight => (int)(Game1.graphics.PreferredBackBufferHeight * 20 / Game1.NativeZoomLevel);
+ private int MaxScrollBoxHeight => (int)(Game1.graphics.PreferredBackBufferHeight * 100 / Game1.NativeZoomLevel);
+ private int ScrollBoxHeight => (int)(Game1.graphics.PreferredBackBufferHeight / Game1.NativeZoomLevel);
private int MaxTextAreaWidth => (int)((Game1.graphics.PreferredBackBufferWidth - 32) / Game1.NativeZoomLevel);
@@ -41,9 +44,13 @@ namespace StardewModdingAPI
internal void InitializeContent(LocalizedContentManager content)
{
- this.scrollbox = new MobileScrollbox(0, 0, this.MaxTextAreaWidth, (int)(Game1.graphics.PreferredBackBufferHeight / Game1.NativeZoomLevel), this.MaxScrollBoxHeight,
- new Rectangle(0, 0, (int)(Game1.graphics.PreferredBackBufferWidth / Game1.NativeZoomLevel), (int)(Game1.graphics.PreferredBackBufferHeight / Game1.NativeZoomLevel)));
this.smallFont = content.Load(@"Fonts\SmallFont");
+ Game1.mobileSpriteSheet = content.Load(@"LooseSprites\\MobileAtlas_manually_made");
+ this.scrollbar = new MobileScrollbar(0, 96, 16, this.ScrollBoxHeight - 192);
+ this.scrollbox = new MobileScrollbox(0, 0, this.MaxTextAreaWidth, this.ScrollBoxHeight, this.MaxScrollBoxHeight,
+ new Rectangle(0, 0, (int)(Game1.graphics.PreferredBackBufferWidth / Game1.NativeZoomLevel), this.ScrollBoxHeight),
+ this.scrollbar
+ );
}
public void Show()
@@ -58,6 +65,12 @@ namespace StardewModdingAPI
public override void receiveLeftClick(int x, int y, bool playSound = true)
{
+ if (this.scrollbar.sliderContains(x, y) || this.scrollbar.sliderRunnerContains(x, y))
+ {
+ float num = this.scrollbar.setY(y);
+ this.scrollbox.setYOffsetForScroll(-((int)((num * this.scrollbox.getMaxYOffset()) / 100f)));
+ Game1.playSound("shwip");
+ }
if (this.upperRightCloseButton.bounds.Contains(x, y))
{
@@ -126,6 +139,7 @@ namespace StardewModdingAPI
this.consoleMessageQueue.AddFirst(new KeyValuePair(level, consoleMessage));
if (this.consoleMessageQueue.Count > 2000)
{
+ this.parseTextCache.Remove(this.consoleMessageQueue.Last.Value.Value);
this.consoleMessageQueue.RemoveLast();
}
}
@@ -136,27 +150,39 @@ namespace StardewModdingAPI
this.scrollbox.update(time);
}
- private string _parseText(string text)
+ private LinkedList _parseText(string text)
{
+ if (this.parseTextCache.TryGetValue(text, out LinkedList returnString))
+ {
+ return returnString;
+ }
+ returnString = new LinkedList();
string line = string.Empty;
- string returnString = string.Empty;
string[] strings = text.Split("\n");
foreach (string t in strings)
{
+ if (this.smallFont.MeasureString(t).X < this.MaxTextAreaWidth)
+ {
+ returnString.AddFirst(t);
+ continue;
+ }
string[] wordArray = t.Split(' ');
+ Vector2 masureResult = new Vector2(0,0);
foreach (string word in wordArray)
{
- if (this.smallFont.MeasureString(line + word).X > this.MaxTextAreaWidth)
+ masureResult += this.smallFont.MeasureString(word + " ");
+ if (masureResult.X > this.MaxTextAreaWidth)
{
- returnString = returnString + line + '\n';
+ returnString.AddFirst(line);
line = string.Empty;
+ masureResult = new Vector2(0, 0);
}
line = line + word + ' ';
}
- returnString = returnString + line + '\n';
+ returnString.AddFirst(line);
line = string.Empty;
}
- returnString.TrimEnd('\n');
+ this.parseTextCache.TryAdd(text, returnString);
return returnString;
}
@@ -185,39 +211,52 @@ namespace StardewModdingAPI
public override void draw(SpriteBatch b)
{
+ this.scrollbar.draw(b);
this.scrollbox.setUpForScrollBoxDrawing(b);
lock (this.consoleMessageQueue)
{
float offset = 0;
+ Vector2 size = this.smallFont.MeasureString("Aa");
foreach (var log in this.consoleMessageQueue)
{
- string text = this._parseText(log.Value);
- Vector2 size = this.smallFont.MeasureString(text);
- float y = Game1.game1.screen.Height - size.Y - offset - this.scrollbox.getYOffsetForScroll();
- offset += size.Y;
- switch (log.Key)
+ LinkedList textArray = this._parseText(log.Value);
+ float baseOffset = Game1.game1.screen.Height - this.scrollbox.getYOffsetForScroll();
+ if (baseOffset - size.Y * textArray.Count - offset > this.ScrollBoxHeight)
{
- case ConsoleLogLevel.Critical:
- case ConsoleLogLevel.Error:
- b.DrawString(this.smallFont, text, new Vector2(16, y), Color.Red);
- break;
- case ConsoleLogLevel.Alert:
- case ConsoleLogLevel.Warn:
- b.DrawString(this.smallFont, text, new Vector2(16, y), Color.Orange);
- break;
- case ConsoleLogLevel.Info:
- case ConsoleLogLevel.Success:
- b.DrawString(this.smallFont, text, new Vector2(16, y), Color.AntiqueWhite);
- break;
- case ConsoleLogLevel.Debug:
- case ConsoleLogLevel.Trace:
- b.DrawString(this.smallFont, text, new Vector2(16, y), Color.LightGray);
- break;
- default:
- b.DrawString(this.smallFont, text, new Vector2(16, y), Color.LightGray);
- break;
+ offset += size.Y * textArray.Count;
+ }
+ else
+ {
+ foreach (string text in textArray)
+ {
+ float y = baseOffset - size.Y - offset;
+ if (y < -16)
+ continue;
+ offset += size.Y;
+ switch (log.Key)
+ {
+ case ConsoleLogLevel.Critical:
+ case ConsoleLogLevel.Error:
+ b.DrawString(this.smallFont, text, new Vector2(16, y), Color.Red);
+ break;
+ case ConsoleLogLevel.Alert:
+ case ConsoleLogLevel.Warn:
+ b.DrawString(this.smallFont, text, new Vector2(16, y), Color.Orange);
+ break;
+ case ConsoleLogLevel.Info:
+ case ConsoleLogLevel.Success:
+ b.DrawString(this.smallFont, text, new Vector2(16, y), Color.AntiqueWhite);
+ break;
+ case ConsoleLogLevel.Debug:
+ case ConsoleLogLevel.Trace:
+ b.DrawString(this.smallFont, text, new Vector2(16, y), Color.LightGray);
+ break;
+ default:
+ b.DrawString(this.smallFont, text, new Vector2(16, y), Color.LightGray);
+ break;
+ }
+ }
}
-
if (offset > this.MaxScrollBoxHeight)
{
break;
diff --git a/src/SMAPI/SMainActivity.cs b/src/SMAPI/SMainActivity.cs
index 321090df..127dbd72 100644
--- a/src/SMAPI/SMainActivity.cs
+++ b/src/SMAPI/SMainActivity.cs
@@ -21,6 +21,7 @@ using File = Java.IO.File;
using Microsoft.AppCenter;
using Newtonsoft.Json;
using Microsoft.AppCenter.Crashes;
+using Android.Content;
namespace StardewModdingAPI
{
@@ -178,7 +179,11 @@ namespace StardewModdingAPI
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
- base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
+ try
+ {
+ base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ catch (ActivityNotFoundException) { }
if (this.HasPermissions)
this.OnCreatePartTwo();
}