Merge with latest branch

This commit is contained in:
zhiyang7 2023-01-29 09:24:00 +08:00
parent 3e43d69745
commit a42acb8176
57 changed files with 957 additions and 5677 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ repo. It imports the other MSBuild files as needed.
<!--set platform-->
<DefineConstants Condition="$(OS) == 'Windows_NT'">$(DefineConstants);SMAPI_FOR_WINDOWS</DefineConstants>
<CopyToGameFolder>true</CopyToGameFolder>
<CopyToGameFolder>false</CopyToGameFolder>
<!-- allow mods to be compiled as AnyCPU for compatibility with older platforms -->
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
@ -50,10 +50,10 @@ repo. It imports the other MSBuild files as needed.
<!--find game folder-->
<Import Project="find-game-folder.targets" />
<Target Name="ValidateInstallPath" AfterTargets="BeforeBuild">
<!-- if game path is invalid, show one user-friendly error instead of a slew of reference errors -->
<Error Condition="!Exists('$(GamePath)')" Text="Failed to find the game install path automatically. You can specify where to find it; see https://smapi.io/package/custom-game-path." />
</Target>
<!-- <Target Name="ValidateInstallPath" AfterTargets="BeforeBuild">-->
<!-- &lt;!&ndash; if game path is invalid, show one user-friendly error instead of a slew of reference errors &ndash;&gt;-->
<!-- <Error Condition="!Exists('$(GamePath)')" Text="Failed to find the game install path automatically. You can specify where to find it; see https://smapi.io/package/custom-game-path." />-->
<!-- </Target>-->
<!-- common build settings -->
<PropertyGroup>

View File

@ -8,11 +8,6 @@
<!-- <BUILD_FOR_MOBILE>SAMSUNG</BUILD_FOR_MOBILE>-->
<!-- <BUILD_FOR_MOBILE>GOOGLE_LEGACY</BUILD_FOR_MOBILE>-->
<COMPILE_WITH_PLUGIN>False</COMPILE_WITH_PLUGIN>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == ''">$(DefineConstants);HARMONY_1</DefineConstants>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'GOOGLE_LEGACY'">$(DefineConstants);SMAPI_FOR_MOBILE;ANDROID_TARGET_GOOGLE;ANDROID_TARGET_MOBILE_LEGACY;HARMONY_1</DefineConstants>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'GOOGLE_145'">$(DefineConstants);SMAPI_FOR_MOBILE;ANDROID_TARGET_GOOGLE;ANDROID_TARGET_GOOGLE_145;HARMONY_1</DefineConstants>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'GOOGLE'">$(DefineConstants);SMAPI_FOR_MOBILE;ANDROID_TARGET_GOOGLE;ANDROID_TARGET_GOOGLE_MONOANDROID10;MonoAndroid10;HARMONY_1</DefineConstants>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'AMAZON'">$(DefineConstants);SMAPI_FOR_MOBILE;ANDROID_TARGET_AMAZON;HARMONY_1</DefineConstants>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'SAMSUNG'">$(DefineConstants);SMAPI_FOR_MOBILE;ANDROID_TARGET_SAMSUNG;HARMONY_1</DefineConstants>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'GOOGLE'">$(DefineConstants);SMAPI_FOR_MOBILE;ANDROID_TARGET_GOOGLE;MonoAndroid10</DefineConstants>
</PropertyGroup>
</Project>

View File

@ -17,7 +17,7 @@
<AndroidResgenClass>Resource</AndroidResgenClass>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>

View File

@ -15,7 +15,7 @@ namespace StardewModdingAPI.Internal.ConsoleWriting
private readonly IDictionary<ConsoleLogLevel, ConsoleColor>? Colors;
/// <summary>Whether the current console supports color formatting.</summary>
[MemberNotNullWhen(true, nameof(ColorfulConsoleWriter.Colors))]
// [MemberNotNullWhen(true, nameof(ColorfulConsoleWriter.Colors))]
private bool SupportsColor { get; }

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StardewModdingAPI.Mods.VirtualKeyboard</RootNamespace>
<AssemblyName>VirtualKeyboard</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />

View File

@ -3,8 +3,9 @@
<RootNamespace>StardewModdingAPI</RootNamespace>
<Description>Provides toolkit interfaces which are available to SMAPI mods.</Description>
<TargetFrameworks>net5.0; netstandard2.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<Import Project="..\..\build\common.targets" />
<Import Project="..\..\build\define-constant.targets" />
</Project>

View File

@ -3,9 +3,6 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
#if SMAPI_FOR_WINDOWS
using System.Management;
#endif
using System.Runtime.InteropServices;
using StardewModdingAPI.Toolkit.Utilities;

View File

@ -5,12 +5,14 @@
<Description>A library which encapsulates mod-handling logic for mod managers and tools. Not intended for use by mods.</Description>
<TargetFrameworks>net5.0; netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<Import Project="..\..\build\common.targets" />
<!-- <Import Project="..\..\build\common.targets" />-->
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Pathoschild.Http.FluentClient" Version="4.2.0" />
</ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''">

View File

@ -27,8 +27,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{09CF91E5-5BAB-4650-A200-E5EA9A633046}"
ProjectSection(SolutionItems) = preProject
..\build\common.targets = ..\build\common.targets
..\build\deploy-local-smapi.targets = ..\build\deploy-local-smapi.targets
..\build\define-constant.targets = ..\build\define-constant.targets
..\build\deploy-local-smapi.targets = ..\build\deploy-local-smapi.targets
..\build\find-game-folder.targets = ..\build\find-game-folder.targets
EndProjectSection
EndProject
@ -59,14 +59,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig.Analyz
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests", "SMAPI.Tests\SMAPI.Tests.csproj", "{AA95884B-7097-476E-92C8-D0500DE9D6D1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI", "SMAPI\SMAPI.csproj", "{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Installer", "SMAPI.Installer\SMAPI.Installer.csproj", "{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}"
ProjectSection(ProjectDependencies) = postProject
{0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F}
{491E775B-EAD0-44D4-B6CA-F1FC3E316D33} = {491E775B-EAD0-44D4-B6CA-F1FC3E316D33}
{CD53AD6F-97F4-4872-A212-50C2A0FD3601} = {CD53AD6F-97F4-4872-A212-50C2A0FD3601}
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32} = {EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig", "SMAPI.ModBuildConfig\SMAPI.ModBuildConfig.csproj", "{1B3821E6-D030-402C-B3A1-7CA45C2800EA}"
@ -113,17 +110,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiProvider"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI", "SMAPI\SMAPI.csproj", "{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5
SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5
SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{6c16e948-3e5c-47a7-bf4b-07a7469a87a5}*SharedItemsImports = 13
SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5
SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13
SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5
SMAPI.Internal\SMAPI.Internal.projitems*{ebd13eab-e70b-4d9f-92c2-c34a21e1fa32}*SharedItemsImports = 5
SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
@ -134,15 +123,9 @@ Global
{680B2641-81EA-467C-86A5-0E81CDC57ED0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{680B2641-81EA-467C-86A5-0E81CDC57ED0}.Release|Any CPU.Build.0 = Release|Any CPU
{AA95884B-7097-476E-92C8-D0500DE9D6D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA95884B-7097-476E-92C8-D0500DE9D6D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA95884B-7097-476E-92C8-D0500DE9D6D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA95884B-7097-476E-92C8-D0500DE9D6D1}.Release|Any CPU.Build.0 = Release|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Release|Any CPU.Build.0 = Release|Any CPU
{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Release|Any CPU.Build.0 = Release|Any CPU
{1B3821E6-D030-402C-B3A1-7CA45C2800EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -174,7 +157,6 @@ Global
{ED8E41FA-DDFA-4A77-932E-9853D279A129}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED8E41FA-DDFA-4A77-932E-9853D279A129}.Release|Any CPU.Build.0 = Release|Any CPU
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU
{29CCE9C9-6811-415D-A681-A6D47073924D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -193,6 +175,10 @@ Global
{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.Build.0 = Release|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -207,11 +193,11 @@ Global
{6C16E948-3E5C-47A7-BF4B-07A7469A87A5} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11}
{680B2641-81EA-467C-86A5-0E81CDC57ED0} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11}
{AA95884B-7097-476E-92C8-D0500DE9D6D1} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11}
{29CCE9C9-6811-415D-A681-A6D47073924D} = {6BBCA4D1-213F-4843-B910-DF2D66E3D8CF}
{45D7D2FB-6B70-45D1-A595-6E289D6A3468} = {6BBCA4D1-213F-4843-B910-DF2D66E3D8CF}
{0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5}
{491E775B-EAD0-44D4-B6CA-F1FC3E316D33} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5}
{CD53AD6F-97F4-4872-A212-50C2A0FD3601} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5}
{29CCE9C9-6811-415D-A681-A6D47073924D} = {6BBCA4D1-213F-4843-B910-DF2D66E3D8CF}
{45D7D2FB-6B70-45D1-A595-6E289D6A3468} = {6BBCA4D1-213F-4843-B910-DF2D66E3D8CF}
{4D661178-38FB-43E4-AA5F-9B0406919344} = {09CF91E5-5BAB-4650-A200-E5EA9A633046}
{CAA1488E-842B-433D-994D-1D3D0B5DD125} = {09CF91E5-5BAB-4650-A200-E5EA9A633046}
{3B5BF14D-F612-4C83-9EF6-E3EBFCD08766} = {4D661178-38FB-43E4-AA5F-9B0406919344}
@ -221,4 +207,10 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5
SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{6c16e948-3e5c-47a7-bf4b-07a7469a87a5}*SharedItemsImports = 13
SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13
SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5
EndGlobalSection
EndGlobal

View File

@ -13,11 +13,7 @@ using StardewModdingAPI.Framework.ModLoading;
using StardewModdingAPI.Toolkit.Framework;
using StardewModdingAPI.Toolkit.Utilities;
using StardewValley;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
namespace StardewModdingAPI
{
/// <summary>Contains constants that are accessed before the game itself has been loaded.</summary>
@ -44,6 +40,9 @@ namespace StardewModdingAPI
public static string StardewValleyBasePath { get; } = Path.Combine(EarlyConstants.StorageBasePath, "StardewValley");
/// <summary>The path to the internal folder.</summary>
public static string ExecutionPath { get; } = Path.Combine(EarlyConstants.StardewValleyBasePath, "smapi-internal");
/// <summary>The path to the game folder.</summary>
public static string GamePath { get; } = ExecutionPath;
#else
/// <summary>The path to the game folder.</summary>
public static string GamePath { get; } = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;

View File

@ -91,8 +91,11 @@ namespace StardewModdingAPI
public static bool HasRemotePlayers => Context.IsMultiplayer && !Game1.hasLocalClientsOnly;
/// <summary>Whether the current player is the main player. This is always true in single-player, and true when hosting in multiplayer.</summary>
#if SMAPI_FOR_MOBILE
public static bool IsMainPlayer => Game1.IsMasterGame && Context.ScreenId == 0;// && TitleMenu.subMenu is not FarmhandMenu;
#else
public static bool IsMainPlayer => Game1.IsMasterGame && Context.ScreenId == 0 && TitleMenu.subMenu is not FarmhandMenu;
#endif
/*********
** Public methods

View File

@ -11,11 +11,18 @@ namespace StardewModdingAPI.Events
** Accessors
*********/
/// <summary>The asset names that were invalidated.</summary>
#if SMAPI_FOR_MOBILE
public IReadOnlyCollection<IAssetName> Names { get; }
#else
public IReadOnlySet<IAssetName> Names { get; }
#endif
/// <summary>The <see cref="Names"/> with any locale codes stripped.</summary>
/// <remarks>For example, if <see cref="Names"/> contains a locale like <c>Data/Bundles.fr-FR</c>, this will have the name without locale like <c>Data/Bundles</c>. If the name has no locale, this field is equivalent.</remarks>
#if SMAPI_FOR_MOBILE
public IReadOnlyCollection<IAssetName> NamesWithoutLocale { get; }
#else
public IReadOnlySet<IAssetName> NamesWithoutLocale { get; }
#endif
/*********

View File

@ -88,8 +88,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
#if SMAPI_FOR_MOBILE
this.Reflector = reflection;
#endif
}
this.TryLocalizeKeys = false;
}
@ -140,16 +138,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
".json" => this.LoadDataFile<T>(assetName, file),
".png" => this.LoadImageFile<T>(assetName, file),
".tbin" or ".tmx" => this.LoadMapFile<T>(assetName, file),
".xnb" => {
asset = this.RawLoad<T>(assetName, useCache: false);
if (asset is Map map)
{
this.NormalizeTilesheetPaths(map);
this.FixCustomTilesheetPaths(map, relativeMapPath: assetName);
}
this.ModedLoad<T>(assetName, language)
// this.LoadXnbFile<T>(assetName)
},
".xnb" => this.LoadXnbFile<T>(assetName),
_ => this.HandleUnknownFileType<T>(assetName, file)
};
}
@ -290,7 +279,11 @@ namespace StardewModdingAPI.Framework.ContentManagers
}
// convert to XNA pixel format
#if SMAPI_FOR_MOBILE
var pixels = new Color[rawPixels.Length];
#else
var pixels = GC.AllocateUninitializedArray<Color>(rawPixels.Length);
#endif
for (int i = 0; i < pixels.Length; i++)
{
SKPMColor pixel = rawPixels[i];
@ -322,6 +315,16 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <param name="assetName">The asset name relative to the loader root directory.</param>
private T LoadXnbFile<T>(IAssetName assetName)
{
// #if SMAPI_FOR_MOBILE
// T asset = this.RawLoad<T>(assetName, useCache: false);
// if (asset is Map map)
// {
// this.NormalizeTilesheetPaths(map);
// this.FixCustomTilesheetPaths(map, relativeMapPath: assetName);
// }
//
// return this.ModedLoad<T>(assetName.Name, language);
// #else
if (typeof(IRawTextureData).IsAssignableFrom(typeof(T)))
this.ThrowLoadError(assetName, ContentLoadErrorType.Other, $"can't read XNB file as type {typeof(IRawTextureData)}; that type can only be read from a PNG file.");
@ -340,6 +343,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
}
return asset;
// #endif
}
/// <summary>Handle a request to load a file type that isn't supported by SMAPI.</summary>

View File

@ -41,7 +41,7 @@ namespace StardewModdingAPI.Framework.Input
** Accessors
*********/
/// <summary>Whether the gamepad is currently connected.</summary>
[MemberNotNullWhen(true, nameof(GamePadStateBuilder.ButtonStates))]
// [MemberNotNullWhen(true, nameof(GamePadStateBuilder.ButtonStates))]
public bool IsConnected { get; }

View File

@ -405,7 +405,7 @@ namespace StardewModdingAPI.Framework.ModLoading
}
// find or rewrite code
InstructionMetadata instructionMetadata = new InstructionMetadata();
InstructionMetadata instructionMetadata = new InstructionMetadata(this.Monitor);
IInstructionHandler[] handlers = instructionMetadata.GetHandlers(this.ParanoidMode, platformChanged, this.RewriteMods).ToArray();
RecursiveRewriter rewriter = new RecursiveRewriter(
module: module,

View File

@ -21,7 +21,7 @@ namespace StardewModdingAPI.Framework.ModLoading
public AssemblyLoadStatus Status;
/// <summary>Whether the <see cref="Definition"/> is loaded and ready (i.e. the <see cref="Status"/> is not <see cref="AssemblyLoadStatus.AlreadyLoaded"/> or <see cref="AssemblyLoadStatus.Failed"/>).</summary>
[MemberNotNullWhen(true, nameof(AssemblyParseResult.Definition))]
// [MemberNotNullWhen(true, nameof(AssemblyParseResult.Definition))]
public bool HasDefinition => this.Status == AssemblyLoadStatus.Okay;

View File

@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
return
fieldRef != null
&& fieldRef.DeclaringType.FullName == this.FullTypeName
&& fieldRef.Name == this.FieldName;
&& this.FieldNames.Contains(fieldRef.Name);
}
}
}

View File

@ -82,7 +82,7 @@ namespace StardewModdingAPI.Framework.ModLoading
public ModEntryModel? UpdateCheckData { get; private set; }
/// <inheritdoc />
[MemberNotNullWhen(true, nameof(ModMetadata.ContentPack))]
// [MemberNotNullWhen(true, nameof(ModMetadata.ContentPack))]
[SuppressMessage("ReSharper", "ConditionalAccessQualifierIsNonNullableAccordingToAPIContract", Justification = "The manifest may be null for broken mods while loading.")]
public bool IsContentPack => this.Manifest?.ContentPackFor != null;
@ -184,7 +184,7 @@ namespace StardewModdingAPI.Framework.ModLoading
}
/// <inheritdoc />
[MemberNotNullWhen(true, nameof(IModInfo.Manifest))]
// [MemberNotNullWhen(true, nameof(IModInfo.Manifest))]
public bool HasManifest()
{
return this.Manifest != null;

View File

@ -55,7 +55,7 @@ namespace StardewModdingAPI.Framework.ModLoading
this.Targets = targetAssemblies;
this.TargetReferences = this.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName));
#if SMAPI_FOR_MOBILE
this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(Path.Combine(Constants.ExecutionPath, assembly.Modules.Single().FullyQualifiedName), new ReaderParameters { InMemory = true }));
this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(Path.Combine(Constants.GamePath, assembly.Modules.Single().FullyQualifiedName), new ReaderParameters { InMemory = true }));
#else
this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName, new ReaderParameters { InMemory = true }));
#endif

View File

@ -1,85 +0,0 @@
#if SMAPI_FOR_MOBILE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using StardewValley;
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
public class DebrisMethods : Debris
{
public DebrisMethods(Item item, Vector2 debrisOrigin)
: base()
{
base.init(item, debrisOrigin);
}
public DebrisMethods(int objectIndex, Vector2 debrisOrigin, Vector2 playerPosition)
: base()
{
base.init(objectIndex, debrisOrigin, playerPosition);
}
public DebrisMethods(Item item, Vector2 debrisOrigin, Vector2 targetLocation)
: base()
{
base.init(item, debrisOrigin, targetLocation);
}
public DebrisMethods(string spriteSheet, int numberOfChunks, Vector2 debrisOrigin)
: base()
{
base.init(spriteSheet, numberOfChunks, debrisOrigin);
}
public DebrisMethods(string spriteSheet, Rectangle sourceRect, int numberOfChunks, Vector2 debrisOrigin)
: base()
{
base.init(spriteSheet, sourceRect, numberOfChunks, debrisOrigin);
}
public DebrisMethods(int debrisType, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition)
: base()
{
base.init(debrisType, numberOfChunks, debrisOrigin, playerPosition);
}
public DebrisMethods(int number, Vector2 debrisOrigin, Color messageColor, float scale, Character toHover)
: base()
{
base.init(number, debrisOrigin, messageColor, scale, toHover);
}
public DebrisMethods(int debrisType, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, float velocityMultiplayer)
: base()
{
base.init(debrisType, numberOfChunks, debrisOrigin, playerPosition, velocityMultiplayer);
}
public DebrisMethods(string message, int numberOfChunks, Vector2 debrisOrigin, Color messageColor, float scale, float rotation)
: base()
{
base.init(message, numberOfChunks, debrisOrigin, messageColor, scale, rotation);
}
public DebrisMethods(string spriteSheet, Rectangle sourceRect, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, int groundLevel)
: base()
{
base.init(spriteSheet, sourceRect, numberOfChunks, debrisOrigin, playerPosition, groundLevel);
}
public DebrisMethods(int type, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, int groundLevel, int color = -1)
: base()
{
base.init(type, numberOfChunks, debrisOrigin, playerPosition, groundLevel, color);
}
public DebrisMethods(string spriteSheet, Rectangle sourceRect, int numberOfChunks, Vector2 debrisOrigin, Vector2 playerPosition, int groundLevel, int sizeOfSourceRectSquares)
: base()
{
base.init(spriteSheet, sourceRect, numberOfChunks, debrisOrigin, playerPosition, groundLevel, sizeOfSourceRectSquares);
}
}
}
#endif

View File

@ -11,6 +11,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
public class Game1Methods : Game1
{
#if SMAPI_LEGACY_PATCH
public static RainDrop[] RainDropsProp => (typeof(RainManager).GetField("_rainDropList", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(RainManager.Instance) as List<RainDrop>).ToArray();
public static bool IsRainingProp
@ -45,6 +46,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
RainManager.Instance.Update(Game1.currentGameTime);
}
#endif
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public static new void warpFarmer(string locationName, int tileX, int tileY, bool flip)
@ -54,7 +56,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
public static void removeSquareDebrisFromTile(int tileX, int tileY)
{
Game1.currentLocation.debris.debrisNetCollection.Filter(debris => {
Game1.currentLocation.debris.Filter(debris => {
if ((debris.debrisType == 2) && (((int)(debris.Chunks[0].position.X / 64f)) == tileX))
{
return (debris.chunkFinalYLevel / 0x40) != tileY;

View File

@ -1,22 +1,14 @@
#if SMAPI_FOR_MOBILE
using System.Reflection;
using System.Reflection.Emit;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
public class HarmonyInstanceMethods
{
public static MethodInfo Patch(
#if HARMONY_2
Harmony instance,
#else
HarmonyInstance instance,
#endif
MethodBase original,
HarmonyMethod prefix = null,
HarmonyMethod postfix = null,
@ -33,22 +25,14 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
return null;
}
public static void PatchAll(
#if HARMONY_2
Harmony instance
#else
HarmonyInstance instance
#endif
)
{
if (Constants.HarmonyEnabled)
instance.PatchAll();
}
public static void PatchAllToAssembly(
#if HARMONY_2
Harmony instance,
#else
HarmonyInstance instance,
#endif
Assembly assembly)
{
if (Constants.HarmonyEnabled)

View File

@ -10,11 +10,14 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
public class IClickableMenuMethods : IClickableMenu
{
#if SMAPI_LEGACY_PATCH
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public static new void drawHoverText(SpriteBatch b, string text, SpriteFont font, int xOffset = 0, int yOffset = 0, int moneyAmounttoDisplayAtBottom = -1, string boldTitleText = null, int healAmountToDisplay = -1, string[] buffIconsToDsiplay = null, Item hoveredItem = null, int currencySymbol = 0, int extraItemToShowIndex = -1, int extraItemToShowAmount = -1, int overideX = -1, int overrideY = -1, float alpha = 1, CraftingRecipe craftingIngrediants = null, IList<Item> additional_craft_materials = null)
{
drawHoverText(b, text, font, xOffset, yOffset, moneyAmounttoDisplayAtBottom, boldTitleText, healAmountToDisplay, buffIconsToDsiplay, hoveredItem, currencySymbol, extraItemToShowIndex, extraItemToShowAmount, overideX, overrideY, alpha, craftingIngrediants, -1, 80, -1, additional_craft_materials);
}
#endif
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new void drawHorizontalPartition(SpriteBatch b, int yPosition, bool small = false, int red = -1, int green = -1, int blue = -1)

View File

@ -1,22 +0,0 @@
#if SMAPI_FOR_MOBILE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StardewValley;
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
public class NPCMethods : NPC
{
public void reloadSprite()
{
base.reloadSprite(Game1.emergencyLoading);
}
public void checkSchedule(int timeOfDay)
{
base.checkSchedule(timeOfDay, Game1.emergencyLoading);
}
}
}
#endif

View File

@ -25,10 +25,12 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
SpriteText.drawString(b, s, x, y, 999999, -1, 999999, alpha, 0.088f, false, 0, placeHolderWidthText, color, scroll_text_alignment);
}
#if SMAPI_LEGACY_PATCH
public static void drawStringWithScrollBackground(SpriteBatch b, string s, int x, int y, string placeHolderWidthText, float alpha, int color)
{
SpriteText.drawStringWithScrollBackground(b, s, x, y, placeHolderWidthText, alpha, color, 0.088f);
}
#endif
}
}
#endif

View File

@ -1,19 +0,0 @@
#if SMAPI_FOR_MOBILE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using StardewValley;
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
public class WeatherDebrisMethods : WeatherDebris
{
public WeatherDebrisMethods(Vector2 position, int which, float rotationVelocity, float dx, float dy)
: base(position, which, dx, dy)
{
}
}
}
#endif

View File

@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
@ -27,10 +23,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
*********/
/// <summary>Construct an instance.</summary>
/// <param name="rewriteReferencesToAssemblies">The assembly names to which to rewrite broken references.</param>
public HeuristicFieldAccessibilityRewriter(string[] rewriteReferencesToAssemblies)
public HeuristicFieldAccessibilityRewriter(HashSet<string> rewriteReferencesToAssemblies)
: base(defaultPhrase: "field visibility changed to private") // ignored since we specify phrases
{
this.RewriteReferencesToAssemblies = new HashSet<string>(rewriteReferencesToAssemblies);
this.RewriteReferencesToAssemblies = rewriteReferencesToAssemblies;
}
/// <inheritdoc />

View File

@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Harmony;
using HarmonyLib;
using Mono.Cecil;
using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework;
@ -15,7 +15,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
** Fields
*********/
/// <summary>The assembly names to which to heuristically detect broken references.</summary>
private readonly HashSet<string> ValidateReferencesToAssemblies;
private readonly ISet<string> ValidateReferencesToAssemblies;
/*********
@ -23,10 +23,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders
*********/
/// <summary>Construct an instance.</summary>
/// <param name="validateReferencesToAssemblies">The assembly names to which to heuristically detect broken references.</param>
public ReferenceToMissingMemberRewriter(string[] validateReferencesToAssemblies)
public ReferenceToMissingMemberRewriter(ISet<string> validateReferencesToAssemblies)
: base(defaultPhrase: "")
{
this.ValidateReferencesToAssemblies = new HashSet<string>(validateReferencesToAssemblies);
this.ValidateReferencesToAssemblies = validateReferencesToAssemblies;
}
/// <inheritdoc />

View File

@ -25,10 +25,18 @@ namespace StardewModdingAPI.Framework
private readonly LogFileManager LogFile;
/// <summary>The maximum length of the <see cref="LogLevel"/> values.</summary>
#if SMAPI_FOR_MOBILE
private static readonly int MaxLevelLength = ((LogLevel[]) Enum.GetValues(typeof (LogLevel))).Max(level => level.ToString().Length);
#else
private static readonly int MaxLevelLength = Enum.GetValues<LogLevel>().Max(level => level.ToString().Length);
#endif
/// <summary>The cached representation for each level when added to a log header.</summary>
#if SMAPI_FOR_MOBILE
private static readonly Dictionary<ConsoleLogLevel, string> LogStrings = ((ConsoleLogLevel[]) Enum.GetValues(typeof (ConsoleLogLevel))).ToDictionary(level => level, level => level.ToString().ToUpper().PadRight(Monitor.MaxLevelLength));
#else
private static readonly Dictionary<ConsoleLogLevel, string> LogStrings = Enum.GetValues<ConsoleLogLevel>().ToDictionary(level => level, level => level.ToString().ToUpper().PadRight(Monitor.MaxLevelLength));
#endif
/// <summary>A cache of messages that should only be logged once.</summary>
private readonly HashSet<LogOnceCacheKey> LogOnceCache = new();

View File

@ -51,6 +51,7 @@ using StardewModdingAPI.Toolkit.Utilities;
using StardewModdingAPI.Toolkit.Utilities.PathLookups;
using StardewModdingAPI.Utilities;
using StardewValley;
using StardewValley.Menus;
#if SMAPI_FOR_MOBILE
using StardewValley.Mobile;
#endif
@ -111,10 +112,7 @@ namespace StardewModdingAPI.Framework
private SGameRunner Game = null!; // initialized very early
#endif
/// <summary>Manages input visible to the game.</summary>
private SInputState Input => SGame.Input;
/// <summary>The game's core multiplayer utility.</summary>
private SMultiplayer Multiplayer => SGame.Multiplayer;
private SInputState Input => Instance.Input;
/// <summary>SMAPI's content manager.</summary>
private ContentCoordinator ContentCore = null!; // initialized very early
@ -166,8 +164,11 @@ namespace StardewModdingAPI.Framework
#endif
/// <summary>A list of queued commands to parse and execute.</summary>
#if SMAPI_FOR_MOBILE
internal readonly CommandQueue RawCommandQueue = new();
#else
private readonly CommandQueue RawCommandQueue = new();
#endif
/// <summary>A list of commands to execute on each screen.</summary>
private readonly PerScreen<List<QueuedCommand>> ScreenCommandQueue = new(() => new List<QueuedCommand>());
@ -314,14 +315,14 @@ namespace StardewModdingAPI.Framework
// new ScheduleErrorPatch(this.LogManager.MonitorForGame)
// );
// add exit handler
this.CancellationToken.Token.Register(() =>
{
if (this.IsGameRunning)
{
this.LogManager.WriteCrashLog();
this.Game.Exit();
}
});
// this.CancellationToken.Token.Register(() =>
// {
// if (this.IsGameRunning)
// {
// this.LogManager.WriteCrashLog();
// this.Game.Exit();
// }
// });
// set window titles
this.UpdateWindowTitles();
@ -1677,6 +1678,7 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log("Checking for updates...");
#if !SMAPI_FOR_MOBILE
// check SMAPI version
{
ISemanticVersion? updateFound = null;

File diff suppressed because it is too large Load Diff

View File

@ -53,6 +53,12 @@ namespace StardewModdingAPI.Framework
/// <summary>The singleton instance.</summary>
public static SGameRunner Instance => (SGameRunner)GameRunner.instance;
#if SMAPI_FOR_MOBILE
public bool IsGameSuspended;
public bool IsAfterInitialize = false;
#endif
/*********
** Public methods

View File

@ -70,17 +70,19 @@ namespace StardewModdingAPI.Framework.StateTracking
this.Location = location;
// init watchers
this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ? WatcherFactory.ForNetCollection(buildableLocation.buildings) : WatcherFactory.ForImmutableCollection<Building>();
this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ?
WatcherFactory.ForNetCollection($"{this.Name}.{nameof(buildableLocation.buildings)}", buildableLocation.buildings) :
WatcherFactory.ForImmutableCollection<Building>();
#if SMAPI_FOR_MOBILE
this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris.debrisNetCollection);
// this.DebrisWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.debris)}", location.debris);
// this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris.debrisNetCollection);
this.DebrisWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.debris)}", location.debris);
#else
this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris);
#endif
this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection(location.largeTerrainFeatures);
this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters);
this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects);
this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary(location.terrainFeatures);
this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.largeTerrainFeatures)}", location.largeTerrainFeatures);
this.NpcsWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.characters)}", location.characters);
this.ObjectsWatcher = WatcherFactory.ForNetDictionary($"{this.Name}.{nameof(location.netObjects)}", location.netObjects);
this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary($"{this.Name}.{nameof(location.terrainFeatures)}", location.terrainFeatures);
this.FurnitureWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.furniture)}", location.furniture);
this.Watchers.AddRange(new IWatcher[]

View File

@ -60,9 +60,9 @@ namespace StardewModdingAPI.Framework.StateTracking
/// <param name="locations">The game's list of locations.</param>
/// <param name="activeMineLocations">The game's list of active mine locations.</param>
/// <param name="activeVolcanoLocations">The game's list of active volcano locations.</param>
public WorldLocationsTracker(ObservableCollection<GameLocation> locations, IList<MineShaft> activeMineLocations, IList<VolcanoDungeon> activeVolcanoLocations)
public WorldLocationsTracker(IList<GameLocation> locations, IList<MineShaft> activeMineLocations, IList<VolcanoDungeon> activeVolcanoLocations)
{
this.LocationListWatcher = WatcherFactory.ForObservableCollection($"{this.Name}.{nameof(locations)}", locations);
this.LocationListWatcher = WatcherFactory.ForReferenceList($"{this.Name}.{nameof(locations)}", locations);
this.MineLocationListWatcher = WatcherFactory.ForReferenceList($"{this.Name}.{nameof(activeMineLocations)}", activeMineLocations);
this.VolcanoLocationListWatcher = WatcherFactory.ForReferenceList($"{this.Name}.{nameof(activeVolcanoLocations)}", activeVolcanoLocations);
}

View File

@ -41,7 +41,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Set the current locale and pre-cache translations.</summary>
/// <param name="locale">The current locale.</param>
/// <param name="localeEnum">The game's current language code.</param>
[MemberNotNull(nameof(Translator.ForLocale), nameof(Translator.Locale))]
// [MemberNotNull(nameof(Translator.ForLocale), nameof(Translator.Locale))]
public void SetLocale(string locale, LocalizedContentManager.LanguageCode localeEnum)
{
this.Locale = locale.ToLower().Trim();

View File

@ -57,7 +57,7 @@ namespace StardewModdingAPI.Framework
/// <summary>Construct an instance.</summary>
/// <param name="inputState">Manages input visible to the game.</param>
/// <param name="gameLocations">The observable list of game locations.</param>
public WatcherCore(SInputState inputState, ObservableCollection<GameLocation> gameLocations)
public WatcherCore(SInputState inputState, IList<GameLocation> gameLocations)
{
// init watchers
this.CursorWatcher = WatcherFactory.ForEquatable(nameof(inputState.CursorPosition), () => inputState.CursorPosition);

View File

@ -19,7 +19,7 @@ namespace StardewModdingAPI
bool IsSplitScreen { get; }
/// <summary>Whether the player has SMAPI installed.</summary>
[MemberNotNullWhen(true, nameof(IMultiplayerPeer.Platform), nameof(IMultiplayerPeer.GameVersion), nameof(IMultiplayerPeer.ApiVersion), nameof(IMultiplayerPeer.Mods))]
// [MemberNotNullWhen(true, nameof(IMultiplayerPeer.Platform), nameof(IMultiplayerPeer.GameVersion), nameof(IMultiplayerPeer.ApiVersion), nameof(IMultiplayerPeer.Mods))]
bool HasSmapi { get; }
/// <summary>The player's screen ID, if applicable.</summary>

View File

@ -444,7 +444,7 @@ namespace StardewModdingAPI.Metadata
return true;
#if SMAPI_FOR_MOBILE
case "loosesprites\\mobileatlas_manually_made": // Game1.LoadContent
case "loosesprites/mobileatlas_manually_made": // Game1.LoadContent
Game1.mobileSpriteSheet = content.Load<Texture2D>(key);
Game1.dayTimeMoneyBox.questButton.texture = Game1.mobileSpriteSheet;
Game1.dayTimeMoneyBox.buttonF8.texture = Game1.mobileSpriteSheet;
@ -452,49 +452,6 @@ namespace StardewModdingAPI.Metadata
return true;
#endif
/****
** Content\TileSheets
****/
case "tilesheets\\critters": // Critter constructor
this.ReloadCritterTextures(content, key);
return true;
case "tilesheets\\crops": // Game1.LoadContent
Game1.cropSpriteSheet = content.Load<Texture2D>(key);
return true;
case "tilesheets\\debris": // Game1.LoadContent
Game1.debrisSpriteSheet = content.Load<Texture2D>(key);
return true;
case "tilesheets\\emotes": // Game1.LoadContent
Game1.emoteSpriteSheet = content.Load<Texture2D>(key);
return true;
case "tilesheets\\furniture": // Game1.LoadContent
Furniture.furnitureTexture = content.Load<Texture2D>(key);
return true;
case "tilesheets\\projectiles": // Game1.LoadContent
Projectile.projectileSheet = content.Load<Texture2D>(key);
return true;
case "tilesheets\\rain": // Game1.LoadContent
Game1.rainTexture = content.Load<Texture2D>(key);
return true;
case "tilesheets\\tools": // Game1.ResetToolSpriteSheet
#if SMAPI_FOR_MOBILE
Game1.toolSpriteSheet = content.Load<Texture2D>(key);
#else
Game1.ResetToolSpriteSheet();
#endif
return true;
case "tilesheets\\weapons": // Game1.LoadContent
Tool.weaponsTexture = content.Load<Texture2D>(key);
return true;
case "loosesprites/suspensionbridge": // SuspensionBridge constructor
return changed | (!ignoreWorld && this.UpdateSuspensionBridges(content, assetName));

View File

@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Events;
@ -29,7 +25,7 @@ namespace StardewModdingAPI.Metadata
*********/
/// <summary>The assembly names to which to heuristically detect broken references.</summary>
/// <remarks>The current implementation only works correctly with assemblies that should always be present.</remarks>
private readonly ISet<string> ValidateReferencesToAssemblies = new HashSet<string> { "StardewModdingAPI", "Stardew Valley", "StardewValley", "Netcode" };
private readonly HashSet<string> ValidateReferencesToAssemblies = new() { "StardewModdingAPI", "Stardew Valley", "StardewValley", "Netcode" };
private readonly IMonitor Monitor;
@ -57,9 +53,13 @@ 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
@ -67,10 +67,12 @@ namespace StardewModdingAPI.Metadata
#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));
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(WeatherDebrisManager), "debrisWeather","weatherDebrisList", "Instance");
// 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 TypeFieldToAnotherTypeFieldRewriter(typeof(GameLocation), typeof(DebrisManager), "debris", this.Monitor, "debrisNetCollection");
// Menu fix
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods), "trashCan", nameof(MenuWithInventoryMethods.TrashCanProp));
@ -89,22 +91,16 @@ namespace StardewModdingAPI.Metadata
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(NPC), typeof(NPCMethods));
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(WeatherDebris), typeof(WeatherDebrisMethods));
yield return new MethodParentRewriter(typeof(Debris), typeof(DebrisMethods));
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));
//Field Rewriters
yield return new FieldReplaceRewriter(typeof(ItemGrabMenu), "context", "specialObject");
#endif
// heuristic rewrites
@ -129,15 +125,9 @@ namespace StardewModdingAPI.Metadata
// MonoMod fix
if (!Constants.HarmonyEnabled)
{
#if HARMONY_2
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");
#else
yield return new MethodToAnotherStaticMethodRewriter(typeof(HarmonyInstance), (method) => method.Name == "Patch", typeof(HarmonyInstanceMethods), "Patch");
yield return new MethodToAnotherStaticMethodRewriter(typeof(HarmonyInstance), (method) => method.Name == "PatchAll" && method.Parameters.Count == 0, typeof(HarmonyInstanceMethods), "PatchAll");
yield return new MethodToAnotherStaticMethodRewriter(typeof(HarmonyInstance), (method) => method.Name == "PatchAll" && method.Parameters.Count == 1, typeof(HarmonyInstanceMethods), "PatchAllToAssembly");
#endif
}
if(Constants.RewriteMissing)

View File

@ -0,0 +1,7 @@
using System.ComponentModel;
namespace System.Runtime.CompilerServices
{
[EditorBrowsable(EditorBrowsableState.Never)]
internal class IsExternalInit{}
}

View File

@ -0,0 +1,23 @@
namespace System;
using Internal.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
public static class MobileMemoryExtension
{
/// <summary>Indicates whether a specified value is found in a read-only span. Values are compared using IEquatable{T}.Equals(T).</summary>
/// <param name="span">The span to search.</param>
/// <param name="value">The value to search for.</param>
/// <typeparam name="T">The type of the span.</typeparam>
/// <returns>
/// <see langword="true" /> if found, <see langword="false" /> otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains<T>(this ReadOnlySpan<T> span, T value) where T : IEquatable<T>
{
return span.IndexOf(value) >= 0;
}
}

View File

@ -0,0 +1,34 @@
namespace System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
public static class MobileTypeExtension
{
/// <summary>Determines whether the current type can be assigned to a variable of the specified <paramref name="targetType" />.</summary>
/// <param name="targetType">The type to compare with the current type.</param>
/// <returns>
/// <see langword="true" /> if any of the following conditions is true:
///
/// - The current instance and <paramref name="targetType" /> represent the same type.
///
/// - The current type is derived either directly or indirectly from <paramref name="targetType" />. The current type is derived directly from <paramref name="targetType" /> if it inherits from <paramref name="targetType" />; the current type is derived indirectly from <paramref name="targetType" /> if it inherits from a succession of one or more classes that inherit from <paramref name="targetType" />.
///
/// - <paramref name="targetType" /> is an interface that the current type implements.
///
/// - The current type is a generic type parameter, and <paramref name="targetType" /> represents one of the constraints of the current type.
///
/// - The current type represents a value type, and <paramref name="targetType" /> represents <c>Nullable&lt;c&gt;</c> (<c>Nullable(Of c)</c> in Visual Basic).
///
/// <see langword="false" /> if none of these conditions are true, or if <paramref name="targetType" /> or <see langword="this" /> is <see langword="null" />.</returns>
public static bool IsAssignableTo(this Type type, [NotNullWhen(true)] Type? targetType) => (object) targetType != null && targetType.IsAssignableFrom(type);
}

View File

@ -4,13 +4,9 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using Microsoft.Xna.Framework;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
using StardewValley;
using StardewValley.Buildings;
using StardewValley.Characters;
@ -21,7 +17,7 @@ namespace StardewModdingAPI.Patches
/// <remarks>Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
[SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
internal class JunimoHarvesterPatch : IHarmonyPatch
internal class JunimoHarvesterPatch : BasePatcher
{
/*********
** Fields
@ -43,22 +39,9 @@ namespace StardewModdingAPI.Patches
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
/// <param name="monitorForGame">Writes messages to the console and log file on behalf of the game.</param>
public JunimoHarvesterPatch(IMonitor monitor)
{
Monitor = monitor;
}
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
public void Apply(
#if HARMONY_2
Harmony harmony
#else
HarmonyInstance harmony
#endif
)
public override void Apply(Harmony harmony, IMonitor monitor)
{
harmony.Patch(
original: AccessTools.DeclaredConstructor(typeof(JunimoHarvester), new System.Type[] { typeof(Vector2), typeof(JunimoHut), typeof(int), typeof(Color?)}),
@ -67,6 +50,13 @@ namespace StardewModdingAPI.Patches
);
}
/// <summary>Construct an instance.</summary>
/// <param name="monitorForGame">Writes messages to the console and log file on behalf of the game.</param>
public JunimoHarvesterPatch(IMonitor monitor)
{
Monitor = monitor;
}
/*********
** Private methods

View File

@ -1,12 +1,8 @@
#if SMAPI_FOR_MOBILE
using System;
using System.Diagnostics.CodeAnalysis;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
using StardewValley;
using StardewValley.Characters;
@ -16,7 +12,7 @@ namespace StardewModdingAPI.Patches
/// <remarks>Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
[SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
internal class LocationSwitchPatch : IHarmonyPatch
internal class LocationSwitchPatch : BasePatcher
{
/*********
** Fields
@ -47,13 +43,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
public void Apply(
#if HARMONY_2
Harmony harmony
#else
HarmonyInstance harmony
#endif
)
public override void Apply(Harmony harmony, IMonitor monitor)
{
harmony.Patch(
original: AccessTools.Property(typeof(Game1), "currentLocation").SetMethod,

View File

@ -3,19 +3,15 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Microsoft.AppCenter.Crashes;
#if HARMONY_2
// using Microsoft.AppCenter.Crashes;
using HarmonyLib;
#else
using Harmony;
#endif
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
using StardewValley;
namespace StardewModdingAPI.Patches
{
internal class MusicBankPatch : IHarmonyPatch
internal class MusicBankPatch : BasePatcher
{
/*********
** Accessors
@ -37,7 +33,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
public void Apply(HarmonyInstance harmony)
public override void Apply(Harmony harmony, IMonitor monitor)
{
harmony.Patch(AccessTools.Method(typeof(Game1), "FetchMusicXWBPath"),
new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(MusicBankPatch.Game_FetchMusicXWBPathPrefix))));
@ -68,7 +64,7 @@ namespace StardewModdingAPI.Patches
}
catch (System.Exception ex)
{
Microsoft.AppCenter.Crashes.Crashes.TrackError(ex, (IDictionary<string, string>) null, Array.Empty<ErrorAttachmentLog>());
// Microsoft.AppCenter.Crashes.Crashes.TrackError(ex, (IDictionary<string, string>) null, Array.Empty<ErrorAttachmentLog>());
return true;
}
__result = str;

View File

@ -2,18 +2,14 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
using StardewValley;
namespace StardewModdingAPI.Patches
{
internal class OnAppPausePatch : IHarmonyPatch
internal class OnAppPausePatch : BasePatcher
{
/*********
** Accessors
@ -35,19 +31,11 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2
public void Apply(Harmony harmony)
public override void Apply(Harmony harmony, IMonitor monitor)
{
harmony.Patch(AccessTools.Method(typeof(Game1), nameof(Game1.OnAppPause)),
finalizer:new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(OnAppPausePatch.Game_OnAppPauseFinalizer))));
finalizer: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(OnAppPausePatch.Game_OnAppPauseFinalizer))));
}
#else
public void Apply(HarmonyInstance harmony)
{
harmony.Patch(AccessTools.Method(typeof(Game1), nameof(Game1.OnAppPause)),
new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(OnAppPausePatch.Game_OnAppPausePrefix))));
}
#endif
/*********
** Private methods
@ -55,36 +43,16 @@ namespace StardewModdingAPI.Patches
/// <summary>The method to call instead of <see cref="StardewValley.Game1.OnAppPause"/>.</summary>
/// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
#if HARMONY_2
private static Exception Game_OnAppPauseFinalizer(Exception __exception)
{
if (__exception != null)
{
OnAppPausePatch.Monitor.Log($"Failed during OnAppPause method :\n{__exception.InnerException ?? __exception}", LogLevel.Error);
}
return null;
}
#else
private static bool Game_OnAppPausePrefix(Game1 __instance, MethodInfo __originalMethod)
{
const string key = nameof(OnAppPausePatch.Game_OnAppPausePrefix);
if (!PatchHelper.StartIntercept(key))
return true;
try
{
__originalMethod.Invoke(__instance, new object[] { });
}
catch (Exception ex)
{
OnAppPausePatch.Monitor.Log($"Failed during OnAppPause method :\n{ex.InnerException ?? ex}", LogLevel.Error);
}
finally
{
PatchHelper.StopIntercept(key);
}
return false;
}
}
#endif
}
#endif

View File

@ -2,19 +2,15 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
using StardewValley;
namespace StardewModdingAPI.Patches
{
internal class SaveBackupPatch : IHarmonyPatch
internal class SaveBackupPatch : BasePatcher
{
/*********
** Accessors
@ -44,8 +40,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2
public void Apply(Harmony harmony)
public override void Apply(Harmony harmony, IMonitor monitor)
{
MethodInfo makeFullBackup = AccessTools.Method(typeof(Game1), nameof(Game1.MakeFullBackup));
MethodInfo saveWholeBackup = AccessTools.Method(typeof(Game1), nameof(Game1.saveWholeBackup));
@ -56,25 +51,13 @@ namespace StardewModdingAPI.Patches
harmony.Patch(makeFullBackup, new HarmonyMethod(prefix), finalizer: new HarmonyMethod(finalizer));
harmony.Patch(saveWholeBackup, new HarmonyMethod(prefix), finalizer: new HarmonyMethod(finalizer));
}
#else
public void Apply(HarmonyInstance harmony)
{
MethodInfo makeFullBackup = AccessTools.Method(typeof(Game1), nameof(Game1.MakeFullBackup));
MethodInfo saveWholeBackup = AccessTools.Method(typeof(Game1), nameof(Game1.saveWholeBackup));
MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(SaveBackupPatch.GameSave_Prefix));
harmony.Patch(makeFullBackup, new HarmonyMethod(prefix));
harmony.Patch(saveWholeBackup, new HarmonyMethod(prefix));
}
#endif
/*********
** Private methods
*********/
/// <summary>The method to call instead of <see cref="StardewValley.Object.getDescription"/>.</summary>
/// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
#if HARMONY_2
private static bool GameSave_Prefix()
{
SaveBackupPatch.Events.Saving.RaiseEmpty();
@ -92,30 +75,6 @@ namespace StardewModdingAPI.Patches
SaveBackupPatch.Events.Saved.RaiseEmpty();
return null;
}
#else
private static bool GameSave_Prefix(MethodInfo __originalMethod)
{
const string key = nameof(SaveBackupPatch.GameSave_Prefix);
if (!PatchHelper.StartIntercept(key))
return true;
SaveBackupPatch.Events.Saving.RaiseEmpty();
try
{
__originalMethod.Invoke(null, new object[] { });
}
catch (Exception ex)
{
SaveBackupPatch.Monitor.Log($"Failed to save the game :\n{ex.InnerException ?? ex}", LogLevel.Error);
Game1.addHUDMessage(new HUDMessage("An error occurs during save the game.Check the error log for details.", HUDMessage.error_type));
}
finally
{
PatchHelper.StopIntercept(key);
}
SaveBackupPatch.Events.Saved.RaiseEmpty();
return false;
}
#endif
}
}
#endif

View File

@ -4,21 +4,17 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using Microsoft.AppCenter.Crashes;
// using Microsoft.AppCenter.Crashes;
using Microsoft.Xna.Framework;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
using StardewValley;
using StardewValley.Menus;
namespace StardewModdingAPI.Patches
{
internal class SaveGamePatch : IHarmonyPatch
internal class SaveGamePatch : BasePatcher
{
/*********
** Accessors
@ -47,8 +43,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2
public void Apply(Harmony harmony)
public override void Apply(Harmony harmony, IMonitor monitor)
{
harmony.Patch(
original: AccessTools.Method(typeof(SaveGame), "HandleLoadError"),
@ -59,19 +54,6 @@ namespace StardewModdingAPI.Patches
finalizer: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.SaveGameMenu_UpdateFinalizer))
);
}
#else
public void Apply(HarmonyInstance harmony)
{
harmony.Patch(
original: AccessTools.Method(typeof(SaveGame), "HandleLoadError"),
prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.Prefix))
);
harmony.Patch(
original: AccessTools.Method(typeof(SaveGameMenu), "update"),
prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.SaveGameMenu_UpdatePrefix))
);
}
#endif
/*********
** Private methods
@ -138,8 +120,8 @@ namespace StardewModdingAPI.Patches
}
catch (Exception ex)
{
ErrorAttachmentLog[] errorAttachmentLogArray = Array.Empty<ErrorAttachmentLog>();
Crashes.TrackError(ex, null, errorAttachmentLogArray);
// ErrorAttachmentLog[] errorAttachmentLogArray = Array.Empty<ErrorAttachmentLog>();
// Crashes.TrackError(ex, null, errorAttachmentLogArray);
failed = true;
}
}
@ -174,7 +156,6 @@ namespace StardewModdingAPI.Patches
/// <summary>The method to call instead of <see cref="StardewValley.Menus.SaveGameMenu.update"/>.</summary>
/// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
#if HARMONY_2
private static Exception SaveGameMenu_UpdateFinalizer(SaveGameMenu __instance, Exception __exception)
{
if(__exception != null) {
@ -184,29 +165,6 @@ namespace StardewModdingAPI.Patches
}
return null;
}
#else
private static bool SaveGameMenu_UpdatePrefix(SaveGameMenu __instance, GameTime time, MethodInfo __originalMethod)
{
const string key = nameof(SaveGamePatch.SaveGameMenu_UpdatePrefix);
if (!PatchHelper.StartIntercept(key))
return true;
try
{
__originalMethod.Invoke(__instance, new object[] {time});
}
catch (Exception ex)
{
SaveGamePatch.Monitor.Log($"Failed during SaveGameMenu.update method :\n{ex.InnerException ?? ex}", LogLevel.Error);
__instance.complete();
Game1.addHUDMessage(new HUDMessage("An error occurs during save the game.Check the error log for details.", HUDMessage.error_type));
}
finally
{
PatchHelper.StopIntercept(key);
}
return false;
}
#endif
}
}
#endif

View File

@ -1,12 +1,8 @@
#if SMAPI_FOR_MOBILE
using System.Diagnostics.CodeAnalysis;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
using StardewValley.Characters;
namespace StardewModdingAPI.Patches
@ -15,7 +11,7 @@ namespace StardewModdingAPI.Patches
/// <remarks>Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
[SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
internal class SpriteFontPatch : IHarmonyPatch
internal class SpriteFontPatch : BasePatcher
{
/*********
** Fields
@ -46,13 +42,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
public void Apply(
#if HARMONY_2
Harmony harmony
#else
HarmonyInstance harmony
#endif
)
public override void Apply(Harmony harmony, IMonitor monitor)
{
harmony.Patch(
original: AccessTools.Method(typeof(SpriteFont), "MeasureString", new System.Type[] { typeof(string)}),

View File

@ -2,12 +2,8 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
#if HARMONY_2
using HarmonyLib;
#else
using Harmony;
#endif
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Internal.Patching;
namespace StardewModdingAPI.Patches
{
@ -15,7 +11,7 @@ namespace StardewModdingAPI.Patches
/// <remarks>Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments.</remarks>
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
[SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
internal class ThreadSilenceExitPatch : IHarmonyPatch
internal class ThreadSilenceExitPatch : BasePatcher
{
/*********
** Fields
@ -46,23 +42,13 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2
public void Apply(Harmony harmony)
public override void Apply(Harmony harmony, IMonitor monitor)
{
harmony.Patch(
original: AccessTools.Method(Type.GetType("System.Threading.ThreadHelper"), "ThreadStart_Context"),
finalizer: new HarmonyMethod(this.GetType(), nameof(ThreadSilenceExitPatch.ThreadStart_Finalizer))
);
}
#else
public void Apply(HarmonyInstance harmony)
{
harmony.Patch(
original: AccessTools.Method(Type.GetType("System.Threading.ThreadHelper"), "ThreadStart_Context"),
prefix: new HarmonyMethod(this.GetType(), nameof(ThreadSilenceExitPatch.ThreadStart_Finalizer))
);
}
#endif
/*********
** Private methods
@ -70,7 +56,6 @@ namespace StardewModdingAPI.Patches
/// <summary>The method to call instead of <see cref="System.Threading.ThreadHelper.ThreadStart_Context"/>.</summary>
/// <param name="state">The thread context.</param>
/// <returns>Returns whether to execute the original method.</returns>
#if HARMONY_2
private static Exception ThreadStart_Finalizer(Exception __exception)
{
if (__exception != null) {
@ -78,29 +63,6 @@ namespace StardewModdingAPI.Patches
}
return null;
}
#else
private static bool ThreadStart_Finalizer(object state)
{
try
{
object _start = state.GetType().GetField("_start", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(state);
if (_start is ThreadStart)
{
((ThreadStart)_start)();
}
else
{
object _startArg = state.GetType().GetField("_startArg", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(state);
((ParameterizedThreadStart)_start)(_startArg);
}
}
catch (Exception ex)
{
Monitor.Log($"Thread failed:\n{ex.InnerException ?? ex}", LogLevel.Error);
}
return false;
}
#endif
}
}
#endif

View File

@ -14,7 +14,7 @@ namespace StardewModdingAPI
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "13.1.0.5")]
public partial class Resource
{
@ -244,97 +244,73 @@ namespace StardewModdingAPI
public static int action_text = 2131034115;
// aapt resource value: 0x7F050005
public static int appIcon = 2131034117;
public static int async = 2131034117;
// aapt resource value: 0x7F050006
public static int async = 2131034118;
public static int blocking = 2131034118;
// aapt resource value: 0x7F050007
public static int blocking = 2131034119;
public static int chronometer = 2131034119;
// aapt resource value: 0x7F050008
public static int chronometer = 2131034120;
public static int forever = 2131034120;
// aapt resource value: 0x7F050009
public static int description = 2131034121;
public static int icon = 2131034121;
// aapt resource value: 0x7F05000A
public static int forever = 2131034122;
public static int icon_group = 2131034122;
// aapt resource value: 0x7F05000B
public static int icon = 2131034123;
public static int info = 2131034123;
// aapt resource value: 0x7F05000C
public static int icon_group = 2131034124;
public static int italic = 2131034124;
// aapt resource value: 0x7F05000D
public static int info = 2131034125;
public static int line1 = 2131034125;
// aapt resource value: 0x7F05000E
public static int italic = 2131034126;
public static int line3 = 2131034126;
// aapt resource value: 0x7F05000F
public static int line1 = 2131034127;
public static int normal = 2131034127;
// aapt resource value: 0x7F050010
public static int line3 = 2131034128;
public static int notification_background = 2131034128;
// aapt resource value: 0x7F050011
public static int normal = 2131034129;
public static int notification_main_column = 2131034129;
// aapt resource value: 0x7F050012
public static int notificationLayout = 2131034130;
public static int notification_main_column_container = 2131034130;
// aapt resource value: 0x7F050013
public static int notification_background = 2131034131;
public static int right_icon = 2131034131;
// aapt resource value: 0x7F050014
public static int notification_main_column = 2131034132;
public static int right_side = 2131034132;
// aapt resource value: 0x7F050015
public static int notification_main_column_container = 2131034133;
public static int tag_transition_group = 2131034133;
// aapt resource value: 0x7F050016
public static int progress_bar = 2131034134;
public static int tag_unhandled_key_event_manager = 2131034134;
// aapt resource value: 0x7F050017
public static int progress_bar_frame = 2131034135;
public static int tag_unhandled_key_listeners = 2131034135;
// aapt resource value: 0x7F050018
public static int progress_text = 2131034136;
public static int text = 2131034136;
// aapt resource value: 0x7F050019
public static int right_icon = 2131034137;
public static int text2 = 2131034137;
// aapt resource value: 0x7F05001A
public static int right_side = 2131034138;
public static int time = 2131034138;
// aapt resource value: 0x7F05001B
public static int spacer = 2131034139;
// aapt resource value: 0x7F05001C
public static int tag_transition_group = 2131034140;
// aapt resource value: 0x7F05001D
public static int tag_unhandled_key_event_manager = 2131034141;
// aapt resource value: 0x7F05001E
public static int tag_unhandled_key_listeners = 2131034142;
// aapt resource value: 0x7F05001F
public static int text = 2131034143;
// aapt resource value: 0x7F050020
public static int text2 = 2131034144;
// aapt resource value: 0x7F050021
public static int time = 2131034145;
// aapt resource value: 0x7F050022
public static int time_remaining = 2131034146;
// aapt resource value: 0x7F050023
public static int title = 2131034147;
public static int title = 2131034139;
static Id()
{
@ -383,9 +359,6 @@ namespace StardewModdingAPI
// aapt resource value: 0x7F070005
public static int notification_template_part_time = 2131165189;
// aapt resource value: 0x7F070006
public static int status_bar_ongoing_event_progress_bar = 2131165190;
static Layout()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
@ -406,76 +379,7 @@ namespace StardewModdingAPI
public static int hello = 2131230721;
// aapt resource value: 0x7F080002
public static int kilobytes_per_second = 2131230722;
// aapt resource value: 0x7F080003
public static int notification_download_complete = 2131230723;
// aapt resource value: 0x7F080004
public static int notification_download_failed = 2131230724;
// aapt resource value: 0x7F080005
public static int state_completed = 2131230725;
// aapt resource value: 0x7F080006
public static int state_connecting = 2131230726;
// aapt resource value: 0x7F080007
public static int state_downloading = 2131230727;
// aapt resource value: 0x7F080008
public static int state_failed = 2131230728;
// aapt resource value: 0x7F080009
public static int state_failed_cancelled = 2131230729;
// aapt resource value: 0x7F08000A
public static int state_failed_fetching_url = 2131230730;
// aapt resource value: 0x7F08000B
public static int state_failed_sdcard_full = 2131230731;
// aapt resource value: 0x7F08000C
public static int state_failed_unlicensed = 2131230732;
// aapt resource value: 0x7F08000D
public static int state_fetching_url = 2131230733;
// aapt resource value: 0x7F08000E
public static int state_idle = 2131230734;
// aapt resource value: 0x7F08000F
public static int state_paused_by_request = 2131230735;
// aapt resource value: 0x7F080010
public static int state_paused_network_setup_failure = 2131230736;
// aapt resource value: 0x7F080011
public static int state_paused_network_unavailable = 2131230737;
// aapt resource value: 0x7F080012
public static int state_paused_roaming = 2131230738;
// aapt resource value: 0x7F080013
public static int state_paused_sdcard_unavailable = 2131230739;
// aapt resource value: 0x7F080014
public static int state_paused_wifi_disabled = 2131230740;
// aapt resource value: 0x7F080015
public static int state_paused_wifi_unavailable = 2131230741;
// aapt resource value: 0x7F080016
public static int state_unknown = 2131230742;
// aapt resource value: 0x7F080017
public static int status_bar_notification_info_overflow = 2131230743;
// aapt resource value: 0x7F080018
public static int time_remaining = 2131230744;
// aapt resource value: 0x7F080019
public static int time_remaining_notification = 2131230745;
public static int status_bar_notification_info_overflow = 2131230722;
static String()
{
@ -491,40 +395,25 @@ namespace StardewModdingAPI
{
// aapt resource value: 0x7F090000
public static int ButtonBackground = 2131296256;
public static int TextAppearance_Compat_Notification = 2131296256;
// aapt resource value: 0x7F090001
public static int NotificationText = 2131296257;
public static int TextAppearance_Compat_Notification_Info = 2131296257;
// aapt resource value: 0x7F090002
public static int NotificationTextSecondary = 2131296258;
public static int TextAppearance_Compat_Notification_Line2 = 2131296258;
// aapt resource value: 0x7F090003
public static int NotificationTextShadow = 2131296259;
public static int TextAppearance_Compat_Notification_Time = 2131296259;
// aapt resource value: 0x7F090004
public static int NotificationTitle = 2131296260;
public static int TextAppearance_Compat_Notification_Title = 2131296260;
// aapt resource value: 0x7F090005
public static int TextAppearance_Compat_Notification = 2131296261;
public static int Widget_Compat_NotificationActionContainer = 2131296261;
// aapt resource value: 0x7F090006
public static int TextAppearance_Compat_Notification_Info = 2131296262;
// aapt resource value: 0x7F090007
public static int TextAppearance_Compat_Notification_Line2 = 2131296263;
// aapt resource value: 0x7F090008
public static int TextAppearance_Compat_Notification_Time = 2131296264;
// aapt resource value: 0x7F090009
public static int TextAppearance_Compat_Notification_Title = 2131296265;
// aapt resource value: 0x7F09000A
public static int Widget_Compat_NotificationActionContainer = 2131296266;
// aapt resource value: 0x7F09000B
public static int Widget_Compat_NotificationActionText = 2131296267;
public static int Widget_Compat_NotificationActionText = 2131296262;
static Style()
{

View File

@ -108,10 +108,10 @@ namespace StardewModdingAPI
this.isVisible = false;
Game1.activeClickableMenu = null;
Game1.playSound("bigDeSelect");
SMainActivity.Instance.core.CommandQueue.Enqueue(command);
SMainActivity.Instance.core.RawCommandQueue.Add(command);
return;
}
SMainActivity.Instance.core.CommandQueue.Enqueue(command);
SMainActivity.Instance.core.RawCommandQueue.Add(command);
}
}

View File

@ -18,8 +18,8 @@
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFramework>MonoAndroid</TargetFramework>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
<TargetFramework>net5.0-android</TargetFramework>
<AndroidUseAapt2>true</AndroidUseAapt2>
<DefineConstants>$(DefineConstants)</DefineConstants>
</PropertyGroup>
@ -33,7 +33,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>latest</LangVersion>
<LangVersion>8.0</LangVersion>
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
</PropertyGroup>
@ -44,7 +43,7 @@
<DefineConstants>$(DefineConstants);TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>8.0</LangVersion>
<LangVersion>latest</LangVersion>
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
@ -70,7 +69,7 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<Import Project="..\..\build\common.targets" />
<!-- <Import Project="..\..\build\common.targets" />-->
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''">
<PackageReference Include="LargeAddressAware" Version="1.0.6" />
@ -85,7 +84,6 @@
<!-- legacy package; remove in SMAPI 4.0.0 -->
<PackageReference Include="System.Runtime.Caching" Version="5.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''">
<Reference Include="..\..\build\0Harmony.dll" Private="True" />
<Reference Include="Stardew Valley" HintPath="$(GamePath)\Stardew Valley.dll" Private="False" />
@ -115,99 +113,24 @@
<Compile Remove="Resources\Resource.designer.cs" Condition="'$(BUILD_FOR_MOBILE)' == ''" />
</ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''">
<PackageReference Include="Xamarin.Google.Android.Vending.Expansion.Downloader">
<Version>2.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Vending.Expansion.ZipFile">
<Version>2.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Vending.Licensing">
<Version>2.0.0</Version>
</PackageReference>
<PackageReference Include="LargeAddressAware" Version="1.0.5" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains('ANDROID_TARGET_GOOGLE_MONOANDROID10'))">
<ItemGroup Condition="$(DefineConstants.Contains('ANDROID_TARGET_GOOGLE'))">
<Reference Include="StardewValley">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.151\assemblies_decrypt\StardewValley.dll</HintPath>
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\StardewValley.dll</HintPath>
</Reference>
<Reference Include="StardewValley.GameData">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.151\assemblies_decrypt\StardewValley.GameData.dll</HintPath>
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\StardewValley.GameData.dll</HintPath>
</Reference>
<Reference Include="xTile">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.151\assemblies_decrypt\xTile.dll</HintPath>
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\xTile.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains('ANDROID_TARGET_GOOGLE_145'))">
<Reference Include="StardewValley">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\StardewValley.dll</HintPath>
</Reference>
<Reference Include="StardewValley.GameData">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\StardewValley.GameData.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="xTile">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\xTile.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains('ANDROID_TARGET_GOOGLE_LEGACY'))">
<Reference Include="StardewValley">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.4.128\assemblies\StardewValley.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.4.128\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="xTile">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.4.128\assemblies\xTile.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains('ANDROID_TARGET_SAMSUNG'))">
<Reference Include="StardewValley">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\samsung_base_1.4.5.144\assemblies\StardewValley.dll</HintPath>
</Reference>
<Reference Include="StardewValley.GameData">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\samsung_base_1.4.5.144\assemblies\StardewValley.GameData.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\samsung_base_1.4.5.144\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="xTile">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\samsung_base_1.4.5.144\assemblies\xTile.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains('ANDROID_TARGET_AMAZON'))">
<Reference Include="StardewValley">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\amazon_base_1.4.5.144\assemblies\StardewValley.dll</HintPath>
</Reference>
<Reference Include="StardewValley.GameData">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\amazon_base_1.4.5.144\assemblies\StardewValley.GameData.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\amazon_base_1.4.5.144\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="xTile">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\amazon_base_1.4.5.144\assemblies\xTile.dll</HintPath>
<Reference Include="BmFont">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\BmFont.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''">
<PackageReference Include="MonoGame.Framework.Android">
<Version>3.6.0.862</Version>
</PackageReference>
<Reference Include="MonoGame.Framework">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework.Content.Pipeline">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\MonoGame.Framework.Content.Pipeline.dll</HintPath>
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
@ -219,45 +142,39 @@
<Reference Include="0Harmony">
<HintPath>..\..\build\0Harmony.dll</HintPath>
</Reference>
<Reference Include="MonoMod.RuntimeDetour">
<HintPath>..\Loader\libs\MonoMod.RuntimeDetour.dll</HintPath>
</Reference>
<Reference Include="MonoMod.Utils">
<HintPath>..\Loader\libs\MonoMod.Utils.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="SMAPI.Toolkit">
<HintPath>..\SMAPI.Toolkit\bin\Debug\net4.5\SMAPI.Toolkit.dll</HintPath>
<HintPath>..\SMAPI.Toolkit\bin\Debug\netstandard2.0\SMAPI.Toolkit.dll</HintPath>
</Reference>
<Reference Include="SMAPI.Toolkit.CoreInterfaces">
<HintPath>..\SMAPI.Toolkit.CoreInterfaces\bin\Debug\net4.5\SMAPI.Toolkit.CoreInterfaces.dll</HintPath>
<HintPath>..\SMAPI.Toolkit.CoreInterfaces\bin\Debug\netstandard2.0\SMAPI.Toolkit.CoreInterfaces.dll</HintPath>
</Reference>
<Reference Include="TMXTile">
<HintPath>..\Loader\libs\TMXTile.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AppCenter">
<HintPath>..\Loader\libs\Microsoft.AppCenter.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AppCenter.Analytics">
<HintPath>..\Loader\libs\Microsoft.AppCenter.Analytics.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AppCenter.Analytics.Android.Bindings">
<HintPath>..\Loader\libs\Microsoft.AppCenter.Analytics.Android.Bindings.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AppCenter.Android.Bindings">
<HintPath>..\Loader\libs\Microsoft.AppCenter.Android.Bindings.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AppCenter.Crashes">
<HintPath>..\Loader\libs\Microsoft.AppCenter.Crashes.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AppCenter.Crashes.Android.Bindings">
<HintPath>..\Loader\libs\Microsoft.AppCenter.Crashes.Android.Bindings.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.Android">
<Version>3.8.1.303</Version>
</PackageReference>
<PackageReference Include="SkiaSharp">
<Version>2.88.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Compat">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DocumentFile">
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="MonoMod.Common" Version="22.3.5.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Pathoschild.Http.FluentClient" Version="4.2.0" />
<Reference Include="Pintail">
<HintPath>..\..\build\Pintail.dll</HintPath>
</Reference>
<Reference Include="TMXTile">
<HintPath>..\..\build\TMXTile.dll</HintPath>
</Reference>
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
<!-- legacy package; remove in SMAPI 4.0.0 -->
<PackageReference Include="System.Runtime.Caching" Version="5.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''">
<Compile Include="**\*.cs" Exclude="**/.vshistory/**;obj/**" />
@ -274,6 +191,10 @@
<Folder Include="Resources\drawable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" Condition="'$(BUILD_FOR_MOBILE)' != ''" />
<Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" />
<Import Project="..\SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems" Label="Shared" />

View File

@ -7,7 +7,6 @@ using Android.Runtime;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using Android.Views;
using Google.Android.Vending.Licensing;
using System;
using System.Collections.Generic;
using StardewModdingAPI.Framework;
@ -16,9 +15,7 @@ using System.Reflection;
using Java.Interop;
using System.Linq;
using File = Java.IO.File;
using Microsoft.AppCenter;
using Newtonsoft.Json;
using Microsoft.AppCenter.Crashes;
using Android.Content;
using Android.Util;
using Java.Lang;
@ -29,17 +26,9 @@ using Thread = System.Threading.Thread;
namespace StardewModdingAPI
{
[Activity(Label = "SMAPI Stardew Valley", Icon = "@mipmap/ic_launcher", Theme = "@style/Theme.Splash", MainLauncher = true, AlwaysRetainTaskState = true, LaunchMode = LaunchMode.SingleInstance, ScreenOrientation = ScreenOrientation.SensorLandscape, ConfigurationChanges = (ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.Orientation | ConfigChanges.ScreenLayout | ConfigChanges.ScreenSize | ConfigChanges.UiMode))]
#if !ANDROID_TARGET_GOOGLE
public class SMainActivity: MainActivity
#else
public class SMainActivity : MainActivity, ILicenseCheckerCallback, IJavaObject, IDisposable, IJavaPeerable
#endif
{
internal SCore core;
private LicenseChecker _licenseChecker;
#if ANDROID_TARGET_GOOGLE
private ServerManagedPolicyExtended _serverManagedPolicyExtended;
#endif
public static SMainActivity Instance;
@ -124,10 +113,6 @@ namespace StardewModdingAPI
}
catch (Exception) { }
}
Type[] services = {typeof(Microsoft.AppCenter.Analytics.Analytics), typeof(Microsoft.AppCenter.Crashes.Crashes)};
AppCenter.Start(Constants.MicrosoftAppSecret, services);
AppCenter.SetUserId(Constants.ApiVersion.ToString());
}
catch
{
@ -164,7 +149,7 @@ namespace StardewModdingAPI
modPath = "StardewValley/Mods";
}
this.core = new SCore(System.IO.Path.Combine(EarlyConstants.StorageBasePath, modPath), false);
this.core = new SCore(System.IO.Path.Combine(EarlyConstants.StorageBasePath, modPath), false, false);
this.core.RunInteractively();
typeof(MainActivity).GetField("_game1", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(this, this.core.Game);
@ -187,7 +172,6 @@ namespace StardewModdingAPI
SAlertDialogUtil.AlertMessage($"SMAPI failed to initialize: {ex}",
callback: type =>
{
Crashes.TrackError(ex);
this.Finish();
});
}
@ -223,49 +207,8 @@ namespace StardewModdingAPI
private void CheckUsingServerManagedPolicy()
{
#if ANDROID_TARGET_GOOGLE
this._serverManagedPolicyExtended = new ServerManagedPolicyExtended(this, new AESObfuscator(new byte[15]
{
46,
65,
30,
128,
103,
57,
74,
64,
51,
88,
95,
45,
77,
117,
36
}, this.PackageName, Settings.Secure.GetString(this.ContentResolver, "android_id")));
this._licenseChecker = new LicenseChecker(this, this._serverManagedPolicyExtended, "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAry4fecehDpCohQk4XhiIZX9ylIGUThWZxfN9qwvQyTh53hvnpQl/lCrjfflKoPz6gz5jJn6JI1PTnoBy/iXVx1+kbO99qBgJE2V8PS5pq+Usbeqqmqqzx4lEzhiYQ2um92v4qkldNYZFwbTODYPIMbSbaLm7eK9ZyemaRbg9ssAl4QYs0EVxzDK1DjuXilRk28WxiK3lNJTz4cT38bfs4q6Zvuk1vWUvnMqcxiugox6c/9j4zZS5C4+k+WY6mHjUMuwssjCY3G+aImWDSwnU3w9G41q8EoPvJ1049PIi7GJXErusTYZITmqfonyejmSFLPt8LHtux9AmJgFSrC3UhwIDAQAB");
this._licenseChecker.CheckAccess(this);
#endif
}
#if ANDROID_TARGET_GOOGLE
public new void Allow(PolicyResponse response)
{
typeof(MainActivity).GetMethod("CheckToDownloadExpansion", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(this, null);
}
public new void DontAllow(PolicyResponse response)
{
switch (response)
{
case PolicyResponse.Retry:
typeof(MainActivity).GetMethod("WaitThenCheckForValidLicence")?.Invoke(this, null);
break;
case PolicyResponse.Licensed:
typeof(MainActivity).GetMethod("CheckToDownloadExpansion", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(this, null);
break;
}
}
#endif
}
}
#endif

View File

@ -54,7 +54,11 @@ namespace StardewModdingAPI.Utilities
}
// parse buttons
#if SMAPI_FOR_MOBILE
string[] rawButtons = input.Split('+', StringSplitOptions.RemoveEmptyEntries);
#else
string[] rawButtons = input.Split('+', StringSplitOptions.TrimEntries);
#endif
SButton[] buttons = new SButton[rawButtons.Length];
List<string> rawErrors = new List<string>();
for (int i = 0; i < buttons.Length; i++)