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--> <!--set platform-->
<DefineConstants Condition="$(OS) == 'Windows_NT'">$(DefineConstants);SMAPI_FOR_WINDOWS</DefineConstants> <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 --> <!-- allow mods to be compiled as AnyCPU for compatibility with older platforms -->
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch> <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
@ -50,10 +50,10 @@ repo. It imports the other MSBuild files as needed.
<!--find game folder--> <!--find game folder-->
<Import Project="find-game-folder.targets" /> <Import Project="find-game-folder.targets" />
<Target Name="ValidateInstallPath" AfterTargets="BeforeBuild"> <!-- <Target Name="ValidateInstallPath" AfterTargets="BeforeBuild">-->
<!-- if game path is invalid, show one user-friendly error instead of a slew of reference errors --> <!-- &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." /> <!-- <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>-->
<!-- common build settings --> <!-- common build settings -->
<PropertyGroup> <PropertyGroup>

View File

@ -8,11 +8,6 @@
<!-- <BUILD_FOR_MOBILE>SAMSUNG</BUILD_FOR_MOBILE>--> <!-- <BUILD_FOR_MOBILE>SAMSUNG</BUILD_FOR_MOBILE>-->
<!-- <BUILD_FOR_MOBILE>GOOGLE_LEGACY</BUILD_FOR_MOBILE>--> <!-- <BUILD_FOR_MOBILE>GOOGLE_LEGACY</BUILD_FOR_MOBILE>-->
<COMPILE_WITH_PLUGIN>False</COMPILE_WITH_PLUGIN> <COMPILE_WITH_PLUGIN>False</COMPILE_WITH_PLUGIN>
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == ''">$(DefineConstants);HARMONY_1</DefineConstants> <DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'GOOGLE'">$(DefineConstants);SMAPI_FOR_MOBILE;ANDROID_TARGET_GOOGLE;MonoAndroid10</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>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

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

View File

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

View File

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

View File

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

View File

@ -3,9 +3,6 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
#if SMAPI_FOR_WINDOWS
using System.Management;
#endif
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using StardewModdingAPI.Toolkit.Utilities; 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> <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> <TargetFrameworks>net5.0; netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="..\..\build\common.targets" /> <!-- <Import Project="..\..\build\common.targets" />-->
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Pathoschild.Http.FluentClient" Version="4.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''"> <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}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{09CF91E5-5BAB-4650-A200-E5EA9A633046}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
..\build\common.targets = ..\build\common.targets ..\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\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 ..\build\find-game-folder.targets = ..\build\find-game-folder.targets
EndProjectSection EndProjectSection
EndProject EndProject
@ -59,14 +59,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig.Analyz
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests", "SMAPI.Tests\SMAPI.Tests.csproj", "{AA95884B-7097-476E-92C8-D0500DE9D6D1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests", "SMAPI.Tests\SMAPI.Tests.csproj", "{AA95884B-7097-476E-92C8-D0500DE9D6D1}"
EndProject 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Installer", "SMAPI.Installer\SMAPI.Installer.csproj", "{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F}
{491E775B-EAD0-44D4-B6CA-F1FC3E316D33} = {491E775B-EAD0-44D4-B6CA-F1FC3E316D33} {491E775B-EAD0-44D4-B6CA-F1FC3E316D33} = {491E775B-EAD0-44D4-B6CA-F1FC3E316D33}
{CD53AD6F-97F4-4872-A212-50C2A0FD3601} = {CD53AD6F-97F4-4872-A212-50C2A0FD3601} {CD53AD6F-97F4-4872-A212-50C2A0FD3601} = {CD53AD6F-97F4-4872-A212-50C2A0FD3601}
{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32} = {EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig", "SMAPI.ModBuildConfig\SMAPI.ModBuildConfig.csproj", "{1B3821E6-D030-402C-B3A1-7CA45C2800EA}" 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 EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI", "SMAPI\SMAPI.csproj", "{EBD13EAB-E70B-4D9F-92C2-C34A21E1FA32}"
EndProject
Global 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 GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|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.ActiveCfg = Release|Any CPU
{680B2641-81EA-467C-86A5-0E81CDC57ED0}.Release|Any CPU.Build.0 = 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.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.ActiveCfg = Release|Any CPU
{AA95884B-7097-476E-92C8-D0500DE9D6D1}.Release|Any CPU.Build.0 = 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.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.ActiveCfg = Release|Any CPU
{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Release|Any CPU.Build.0 = 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 {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.ActiveCfg = Release|Any CPU
{ED8E41FA-DDFA-4A77-932E-9853D279A129}.Release|Any CPU.Build.0 = 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.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.ActiveCfg = Release|Any CPU
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = 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 {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}.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.ActiveCfg = Release|Any CPU
{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -207,11 +193,11 @@ Global
{6C16E948-3E5C-47A7-BF4B-07A7469A87A5} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} {6C16E948-3E5C-47A7-BF4B-07A7469A87A5} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11}
{680B2641-81EA-467C-86A5-0E81CDC57ED0} = {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} {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} {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5}
{491E775B-EAD0-44D4-B6CA-F1FC3E316D33} = {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} {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} {4D661178-38FB-43E4-AA5F-9B0406919344} = {09CF91E5-5BAB-4650-A200-E5EA9A633046}
{CAA1488E-842B-433D-994D-1D3D0B5DD125} = {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} {3B5BF14D-F612-4C83-9EF6-E3EBFCD08766} = {4D661178-38FB-43E4-AA5F-9B0406919344}
@ -221,4 +207,10 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC} SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC}
EndGlobalSection 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 EndGlobal

View File

@ -13,11 +13,7 @@ using StardewModdingAPI.Framework.ModLoading;
using StardewModdingAPI.Toolkit.Framework; using StardewModdingAPI.Toolkit.Framework;
using StardewModdingAPI.Toolkit.Utilities; using StardewModdingAPI.Toolkit.Utilities;
using StardewValley; using StardewValley;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else
using Harmony;
#endif
namespace StardewModdingAPI namespace StardewModdingAPI
{ {
/// <summary>Contains constants that are accessed before the game itself has been loaded.</summary> /// <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"); public static string StardewValleyBasePath { get; } = Path.Combine(EarlyConstants.StorageBasePath, "StardewValley");
/// <summary>The path to the internal folder.</summary> /// <summary>The path to the internal folder.</summary>
public static string ExecutionPath { get; } = Path.Combine(EarlyConstants.StardewValleyBasePath, "smapi-internal"); 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 #else
/// <summary>The path to the game folder.</summary> /// <summary>The path to the game folder.</summary>
public static string GamePath { get; } = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; 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; 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> /// <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; public static bool IsMainPlayer => Game1.IsMasterGame && Context.ScreenId == 0 && TitleMenu.subMenu is not FarmhandMenu;
#endif
/********* /*********
** Public methods ** Public methods

View File

@ -11,11 +11,18 @@ namespace StardewModdingAPI.Events
** Accessors ** Accessors
*********/ *********/
/// <summary>The asset names that were invalidated.</summary> /// <summary>The asset names that were invalidated.</summary>
#if SMAPI_FOR_MOBILE
public IReadOnlyCollection<IAssetName> Names { get; }
#else
public IReadOnlySet<IAssetName> Names { get; } public IReadOnlySet<IAssetName> Names { get; }
#endif
/// <summary>The <see cref="Names"/> with any locale codes stripped.</summary> /// <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> /// <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; } public IReadOnlySet<IAssetName> NamesWithoutLocale { get; }
#endif
/********* /*********

View File

@ -88,8 +88,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
#if SMAPI_FOR_MOBILE #if SMAPI_FOR_MOBILE
this.Reflector = reflection; this.Reflector = reflection;
#endif #endif
}
this.TryLocalizeKeys = false; this.TryLocalizeKeys = false;
} }
@ -140,16 +138,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
".json" => this.LoadDataFile<T>(assetName, file), ".json" => this.LoadDataFile<T>(assetName, file),
".png" => this.LoadImageFile<T>(assetName, file), ".png" => this.LoadImageFile<T>(assetName, file),
".tbin" or ".tmx" => this.LoadMapFile<T>(assetName, file), ".tbin" or ".tmx" => this.LoadMapFile<T>(assetName, file),
".xnb" => { ".xnb" => this.LoadXnbFile<T>(assetName),
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)
},
_ => this.HandleUnknownFileType<T>(assetName, file) _ => this.HandleUnknownFileType<T>(assetName, file)
}; };
} }
@ -290,7 +279,11 @@ namespace StardewModdingAPI.Framework.ContentManagers
} }
// convert to XNA pixel format // convert to XNA pixel format
#if SMAPI_FOR_MOBILE
var pixels = new Color[rawPixels.Length];
#else
var pixels = GC.AllocateUninitializedArray<Color>(rawPixels.Length); var pixels = GC.AllocateUninitializedArray<Color>(rawPixels.Length);
#endif
for (int i = 0; i < pixels.Length; i++) for (int i = 0; i < pixels.Length; i++)
{ {
SKPMColor pixel = rawPixels[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> /// <param name="assetName">The asset name relative to the loader root directory.</param>
private T LoadXnbFile<T>(IAssetName assetName) 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))) 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."); 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; return asset;
// #endif
} }
/// <summary>Handle a request to load a file type that isn't supported by SMAPI.</summary> /// <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 ** Accessors
*********/ *********/
/// <summary>Whether the gamepad is currently connected.</summary> /// <summary>Whether the gamepad is currently connected.</summary>
[MemberNotNullWhen(true, nameof(GamePadStateBuilder.ButtonStates))] // [MemberNotNullWhen(true, nameof(GamePadStateBuilder.ButtonStates))]
public bool IsConnected { get; } public bool IsConnected { get; }

View File

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

View File

@ -21,7 +21,7 @@ namespace StardewModdingAPI.Framework.ModLoading
public AssemblyLoadStatus Status; 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> /// <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; public bool HasDefinition => this.Status == AssemblyLoadStatus.Okay;

View File

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

View File

@ -55,7 +55,7 @@ namespace StardewModdingAPI.Framework.ModLoading
this.Targets = targetAssemblies; this.Targets = targetAssemblies;
this.TargetReferences = this.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName)); this.TargetReferences = this.Targets.ToDictionary(assembly => assembly, assembly => AssemblyNameReference.Parse(assembly.FullName));
#if SMAPI_FOR_MOBILE #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 #else
this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName, new ReaderParameters { InMemory = true })); this.TargetModules = this.Targets.ToDictionary(assembly => assembly, assembly => ModuleDefinition.ReadModule(assembly.Modules.Single().FullyQualifiedName, new ReaderParameters { InMemory = true }));
#endif #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 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 RainDrop[] RainDropsProp => (typeof(RainManager).GetField("_rainDropList", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(RainManager.Instance) as List<RainDrop>).ToArray();
public static bool IsRainingProp public static bool IsRainingProp
@ -45,6 +46,7 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{ {
RainManager.Instance.Update(Game1.currentGameTime); RainManager.Instance.Update(Game1.currentGameTime);
} }
#endif
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")] [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) 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) 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)) if ((debris.debrisType == 2) && (((int)(debris.Chunks[0].position.X / 64f)) == tileX))
{ {
return (debris.chunkFinalYLevel / 0x40) != tileY; return (debris.chunkFinalYLevel / 0x40) != tileY;

View File

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

View File

@ -10,11 +10,14 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{ {
public class IClickableMenuMethods : IClickableMenu public class IClickableMenuMethods : IClickableMenu
{ {
#if SMAPI_LEGACY_PATCH
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")] [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) 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); 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.")] [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) 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); 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) 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); SpriteText.drawStringWithScrollBackground(b, s, x, y, placeHolderWidthText, alpha, color, 0.088f);
} }
#endif
} }
} }
#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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else
using Harmony;
#endif
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using StardewModdingAPI.Framework.ModLoading.Framework; using StardewModdingAPI.Framework.ModLoading.Framework;
@ -27,10 +23,10 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters
*********/ *********/
/// <summary>Construct an instance.</summary> /// <summary>Construct an instance.</summary>
/// <param name="rewriteReferencesToAssemblies">The assembly names to which to rewrite broken references.</param> /// <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 : base(defaultPhrase: "field visibility changed to private") // ignored since we specify phrases
{ {
this.RewriteReferencesToAssemblies = new HashSet<string>(rewriteReferencesToAssemblies); this.RewriteReferencesToAssemblies = rewriteReferencesToAssemblies;
} }
/// <inheritdoc /> /// <inheritdoc />

View File

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

View File

@ -25,10 +25,18 @@ namespace StardewModdingAPI.Framework
private readonly LogFileManager LogFile; private readonly LogFileManager LogFile;
/// <summary>The maximum length of the <see cref="LogLevel"/> values.</summary> /// <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); 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> /// <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)); 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> /// <summary>A cache of messages that should only be logged once.</summary>
private readonly HashSet<LogOnceCacheKey> LogOnceCache = new(); private readonly HashSet<LogOnceCacheKey> LogOnceCache = new();

View File

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

View File

@ -70,17 +70,19 @@ namespace StardewModdingAPI.Framework.StateTracking
this.Location = location; this.Location = location;
// init watchers // 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 #if SMAPI_FOR_MOBILE
this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris.debrisNetCollection); // this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris.debrisNetCollection);
// this.DebrisWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.debris)}", location.debris); this.DebrisWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.debris)}", location.debris);
#else #else
this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris); this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris);
#endif #endif
this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection(location.largeTerrainFeatures); this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.largeTerrainFeatures)}", location.largeTerrainFeatures);
this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters); this.NpcsWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.characters)}", location.characters);
this.ObjectsWatcher = WatcherFactory.ForNetDictionary(location.netObjects); this.ObjectsWatcher = WatcherFactory.ForNetDictionary($"{this.Name}.{nameof(location.netObjects)}", location.netObjects);
this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary(location.terrainFeatures); this.TerrainFeaturesWatcher = WatcherFactory.ForNetDictionary($"{this.Name}.{nameof(location.terrainFeatures)}", location.terrainFeatures);
this.FurnitureWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.furniture)}", location.furniture); this.FurnitureWatcher = WatcherFactory.ForNetCollection($"{this.Name}.{nameof(location.furniture)}", location.furniture);
this.Watchers.AddRange(new IWatcher[] 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="locations">The game's list of locations.</param>
/// <param name="activeMineLocations">The game's list of active mine 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> /// <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.MineLocationListWatcher = WatcherFactory.ForReferenceList($"{this.Name}.{nameof(activeMineLocations)}", activeMineLocations);
this.VolcanoLocationListWatcher = WatcherFactory.ForReferenceList($"{this.Name}.{nameof(activeVolcanoLocations)}", activeVolcanoLocations); 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> /// <summary>Set the current locale and pre-cache translations.</summary>
/// <param name="locale">The current locale.</param> /// <param name="locale">The current locale.</param>
/// <param name="localeEnum">The game's current language code.</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) public void SetLocale(string locale, LocalizedContentManager.LanguageCode localeEnum)
{ {
this.Locale = locale.ToLower().Trim(); this.Locale = locale.ToLower().Trim();

View File

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

View File

@ -19,7 +19,7 @@ namespace StardewModdingAPI
bool IsSplitScreen { get; } bool IsSplitScreen { get; }
/// <summary>Whether the player has SMAPI installed.</summary> /// <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; } bool HasSmapi { get; }
/// <summary>The player's screen ID, if applicable.</summary> /// <summary>The player's screen ID, if applicable.</summary>

View File

@ -444,7 +444,7 @@ namespace StardewModdingAPI.Metadata
return true; return true;
#if SMAPI_FOR_MOBILE #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.mobileSpriteSheet = content.Load<Texture2D>(key);
Game1.dayTimeMoneyBox.questButton.texture = Game1.mobileSpriteSheet; Game1.dayTimeMoneyBox.questButton.texture = Game1.mobileSpriteSheet;
Game1.dayTimeMoneyBox.buttonF8.texture = Game1.mobileSpriteSheet; Game1.dayTimeMoneyBox.buttonF8.texture = Game1.mobileSpriteSheet;
@ -452,49 +452,6 @@ namespace StardewModdingAPI.Metadata
return true; return true;
#endif #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 case "loosesprites/suspensionbridge": // SuspensionBridge constructor
return changed | (!ignoreWorld && this.UpdateSuspensionBridges(content, assetName)); return changed | (!ignoreWorld && this.UpdateSuspensionBridges(content, assetName));

View File

@ -1,10 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else
using Harmony;
#endif
using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
@ -29,7 +25,7 @@ namespace StardewModdingAPI.Metadata
*********/ *********/
/// <summary>The assembly names to which to heuristically detect broken references.</summary> /// <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> /// <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; private readonly IMonitor Monitor;
@ -57,9 +53,13 @@ namespace StardewModdingAPI.Metadata
yield return new FieldReplaceRewriter() yield return new FieldReplaceRewriter()
.AddField(typeof(DecoratableLocation), "furniture", typeof(GameLocation), nameof(GameLocation.furniture)) .AddField(typeof(DecoratableLocation), "furniture", typeof(GameLocation), nameof(GameLocation.furniture))
.AddField(typeof(Farm), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps)) .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)); .AddField(typeof(MineShaft), "resourceClumps", typeof(GameLocation), nameof(GameLocation.resourceClumps));
#if SMAPI_FOR_MOBILE #if SMAPI_FOR_MOBILE
#if SMAPI_LEGACY_PATCH
// Redirect reference // Redirect reference
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isRaining", nameof(Game1Methods.IsRainingProp)); yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isRaining", nameof(Game1Methods.IsRainingProp));
#if !ANDROID_TARGET_MOBILE_LEGACY #if !ANDROID_TARGET_MOBILE_LEGACY
@ -67,10 +67,12 @@ namespace StardewModdingAPI.Metadata
#endif #endif
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "isDebrisWeather", nameof(Game1Methods.IsDebrisWeatherProp)); 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(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 TypeFieldToAnotherTypePropertyRewriter(typeof(Game1), typeof(Game1Methods), "onScreenMenus", "onScreenMenus");
yield return new PropertyToFieldRewriter(typeof(Game1), "toolSpriteSheet", "toolSpriteSheet"); 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 // Menu fix
yield return new TypeFieldToAnotherTypePropertyRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods), "trashCan", nameof(MenuWithInventoryMethods.TrashCanProp)); 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(Game1), typeof(Game1Methods));
yield return new MethodParentRewriter(typeof(IClickableMenu), typeof(IClickableMenuMethods)); yield return new MethodParentRewriter(typeof(IClickableMenu), typeof(IClickableMenuMethods));
yield return new MethodParentRewriter(typeof(SpriteText), typeof(SpriteTextMethods)); yield return new MethodParentRewriter(typeof(SpriteText), typeof(SpriteTextMethods));
yield return new MethodParentRewriter(typeof(NPC), typeof(NPCMethods));
yield return new MethodParentRewriter(typeof(Utility), typeof(UtilityMethods)); yield return new MethodParentRewriter(typeof(Utility), typeof(UtilityMethods));
//Constructor Rewrites //Constructor Rewrites
yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods)); yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods));
yield return new MethodParentRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods)); 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(InventoryMenu), typeof(InventoryMenuMethods));
yield return new MethodParentRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods)); yield return new MethodParentRewriter(typeof(MenuWithInventory), typeof(MenuWithInventoryMethods));
yield return new MethodParentRewriter(typeof(GameMenu), typeof(GameMenuMethods)); yield return new MethodParentRewriter(typeof(GameMenu), typeof(GameMenuMethods));
yield return new MethodParentRewriter(typeof(CraftingPageMobile), typeof(CraftingPageMobileMethods)); yield return new MethodParentRewriter(typeof(CraftingPageMobile), typeof(CraftingPageMobileMethods));
//Field Rewriters
yield return new FieldReplaceRewriter(typeof(ItemGrabMenu), "context", "specialObject");
#endif #endif
// heuristic rewrites // heuristic rewrites
@ -129,15 +125,9 @@ namespace StardewModdingAPI.Metadata
// MonoMod fix // MonoMod fix
if (!Constants.HarmonyEnabled) 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 == "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 == 0, typeof(HarmonyInstanceMethods), "PatchAll");
yield return new MethodToAnotherStaticMethodRewriter(typeof(Harmony), (method) => method.Name == "PatchAll" && method.Parameters.Count == 1, typeof(HarmonyInstanceMethods), "PatchAllToAssembly"); 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) 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.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else
using Harmony;
#endif
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Internal.Patching;
using StardewValley; using StardewValley;
using StardewValley.Buildings; using StardewValley.Buildings;
using StardewValley.Characters; 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> /// <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", "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.")] [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 ** Fields
@ -43,22 +39,9 @@ namespace StardewModdingAPI.Patches
/********* /*********
** Public methods ** 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> /// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param> /// <param name="harmony">The Harmony instance.</param>
public void Apply( public override void Apply(Harmony harmony, IMonitor monitor)
#if HARMONY_2
Harmony harmony
#else
HarmonyInstance harmony
#endif
)
{ {
harmony.Patch( harmony.Patch(
original: AccessTools.DeclaredConstructor(typeof(JunimoHarvester), new System.Type[] { typeof(Vector2), typeof(JunimoHut), typeof(int), typeof(Color?)}), 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 ** Private methods

View File

@ -1,12 +1,8 @@
#if SMAPI_FOR_MOBILE #if SMAPI_FOR_MOBILE
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else using StardewModdingAPI.Internal.Patching;
using Harmony;
#endif
using StardewModdingAPI.Framework.Patching;
using StardewValley; using StardewValley;
using StardewValley.Characters; 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> /// <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", "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.")] [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 ** Fields
@ -47,13 +43,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary> /// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param> /// <param name="harmony">The Harmony instance.</param>
public void Apply( public override void Apply(Harmony harmony, IMonitor monitor)
#if HARMONY_2
Harmony harmony
#else
HarmonyInstance harmony
#endif
)
{ {
harmony.Patch( harmony.Patch(
original: AccessTools.Property(typeof(Game1), "currentLocation").SetMethod, original: AccessTools.Property(typeof(Game1), "currentLocation").SetMethod,

View File

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

View File

@ -2,18 +2,14 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else
using Harmony;
#endif
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Internal.Patching;
using StardewValley; using StardewValley;
namespace StardewModdingAPI.Patches namespace StardewModdingAPI.Patches
{ {
internal class OnAppPausePatch : IHarmonyPatch internal class OnAppPausePatch : BasePatcher
{ {
/********* /*********
** Accessors ** Accessors
@ -35,19 +31,11 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary> /// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param> /// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2 public override void Apply(Harmony harmony, IMonitor monitor)
public void Apply(Harmony harmony)
{ {
harmony.Patch(AccessTools.Method(typeof(Game1), nameof(Game1.OnAppPause)), 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 ** Private methods
@ -55,36 +43,16 @@ namespace StardewModdingAPI.Patches
/// <summary>The method to call instead of <see cref="StardewValley.Game1.OnAppPause"/>.</summary> /// <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> /// <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.")] [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
#if HARMONY_2
private static Exception Game_OnAppPauseFinalizer(Exception __exception) private static Exception Game_OnAppPauseFinalizer(Exception __exception)
{ {
if (__exception != null) if (__exception != null)
{ {
OnAppPausePatch.Monitor.Log($"Failed during OnAppPause method :\n{__exception.InnerException ?? __exception}", LogLevel.Error); OnAppPausePatch.Monitor.Log($"Failed during OnAppPause method :\n{__exception.InnerException ?? __exception}", LogLevel.Error);
} }
return null; 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 #endif

View File

@ -2,19 +2,15 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else
using Harmony;
#endif
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Internal.Patching;
using StardewValley; using StardewValley;
namespace StardewModdingAPI.Patches namespace StardewModdingAPI.Patches
{ {
internal class SaveBackupPatch : IHarmonyPatch internal class SaveBackupPatch : BasePatcher
{ {
/********* /*********
** Accessors ** Accessors
@ -44,8 +40,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary> /// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param> /// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2 public override void Apply(Harmony harmony, IMonitor monitor)
public void Apply(Harmony harmony)
{ {
MethodInfo makeFullBackup = AccessTools.Method(typeof(Game1), nameof(Game1.MakeFullBackup)); MethodInfo makeFullBackup = AccessTools.Method(typeof(Game1), nameof(Game1.MakeFullBackup));
MethodInfo saveWholeBackup = AccessTools.Method(typeof(Game1), nameof(Game1.saveWholeBackup)); 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(makeFullBackup, new HarmonyMethod(prefix), finalizer: new HarmonyMethod(finalizer));
harmony.Patch(saveWholeBackup, 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 ** Private methods
*********/ *********/
/// <summary>The method to call instead of <see cref="StardewValley.Object.getDescription"/>.</summary> /// <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> /// <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.")] [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
#if HARMONY_2
private static bool GameSave_Prefix() private static bool GameSave_Prefix()
{ {
SaveBackupPatch.Events.Saving.RaiseEmpty(); SaveBackupPatch.Events.Saving.RaiseEmpty();
@ -92,30 +75,6 @@ namespace StardewModdingAPI.Patches
SaveBackupPatch.Events.Saved.RaiseEmpty(); SaveBackupPatch.Events.Saved.RaiseEmpty();
return null; 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 #endif

View File

@ -4,21 +4,17 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else // using Microsoft.AppCenter.Crashes;
using Harmony;
#endif
using Microsoft.AppCenter.Crashes;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Internal.Patching;
using StardewValley; using StardewValley;
using StardewValley.Menus; using StardewValley.Menus;
namespace StardewModdingAPI.Patches namespace StardewModdingAPI.Patches
{ {
internal class SaveGamePatch : IHarmonyPatch internal class SaveGamePatch : BasePatcher
{ {
/********* /*********
** Accessors ** Accessors
@ -47,8 +43,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary> /// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param> /// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2 public override void Apply(Harmony harmony, IMonitor monitor)
public void Apply(Harmony harmony)
{ {
harmony.Patch( harmony.Patch(
original: AccessTools.Method(typeof(SaveGame), "HandleLoadError"), original: AccessTools.Method(typeof(SaveGame), "HandleLoadError"),
@ -59,19 +54,6 @@ namespace StardewModdingAPI.Patches
finalizer: new HarmonyMethod(this.GetType(), nameof(SaveGamePatch.SaveGameMenu_UpdateFinalizer)) 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 ** Private methods
@ -138,8 +120,8 @@ namespace StardewModdingAPI.Patches
} }
catch (Exception ex) catch (Exception ex)
{ {
ErrorAttachmentLog[] errorAttachmentLogArray = Array.Empty<ErrorAttachmentLog>(); // ErrorAttachmentLog[] errorAttachmentLogArray = Array.Empty<ErrorAttachmentLog>();
Crashes.TrackError(ex, null, errorAttachmentLogArray); // Crashes.TrackError(ex, null, errorAttachmentLogArray);
failed = true; failed = true;
} }
} }
@ -174,7 +156,6 @@ namespace StardewModdingAPI.Patches
/// <summary>The method to call instead of <see cref="StardewValley.Menus.SaveGameMenu.update"/>.</summary> /// <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> /// <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.")] [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")]
#if HARMONY_2
private static Exception SaveGameMenu_UpdateFinalizer(SaveGameMenu __instance, Exception __exception) private static Exception SaveGameMenu_UpdateFinalizer(SaveGameMenu __instance, Exception __exception)
{ {
if(__exception != null) { if(__exception != null) {
@ -184,29 +165,6 @@ namespace StardewModdingAPI.Patches
} }
return null; 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 #endif

View File

@ -1,12 +1,8 @@
#if SMAPI_FOR_MOBILE #if SMAPI_FOR_MOBILE
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else
using Harmony;
#endif
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Internal.Patching;
using StardewValley.Characters; using StardewValley.Characters;
namespace StardewModdingAPI.Patches 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> /// <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", "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.")] [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 ** Fields
@ -46,13 +42,7 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary> /// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param> /// <param name="harmony">The Harmony instance.</param>
public void Apply( public override void Apply(Harmony harmony, IMonitor monitor)
#if HARMONY_2
Harmony harmony
#else
HarmonyInstance harmony
#endif
)
{ {
harmony.Patch( harmony.Patch(
original: AccessTools.Method(typeof(SpriteFont), "MeasureString", new System.Type[] { typeof(string)}), original: AccessTools.Method(typeof(SpriteFont), "MeasureString", new System.Type[] { typeof(string)}),

View File

@ -2,12 +2,8 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Threading; using System.Threading;
#if HARMONY_2
using HarmonyLib; using HarmonyLib;
#else using StardewModdingAPI.Internal.Patching;
using Harmony;
#endif
using StardewModdingAPI.Framework.Patching;
namespace StardewModdingAPI.Patches 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> /// <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", "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.")] [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 ** Fields
@ -46,23 +42,13 @@ namespace StardewModdingAPI.Patches
/// <summary>Apply the Harmony patch.</summary> /// <summary>Apply the Harmony patch.</summary>
/// <param name="harmony">The Harmony instance.</param> /// <param name="harmony">The Harmony instance.</param>
#if HARMONY_2 public override void Apply(Harmony harmony, IMonitor monitor)
public void Apply(Harmony harmony)
{ {
harmony.Patch( harmony.Patch(
original: AccessTools.Method(Type.GetType("System.Threading.ThreadHelper"), "ThreadStart_Context"), original: AccessTools.Method(Type.GetType("System.Threading.ThreadHelper"), "ThreadStart_Context"),
finalizer: new HarmonyMethod(this.GetType(), nameof(ThreadSilenceExitPatch.ThreadStart_Finalizer)) 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 ** Private methods
@ -70,7 +56,6 @@ namespace StardewModdingAPI.Patches
/// <summary>The method to call instead of <see cref="System.Threading.ThreadHelper.ThreadStart_Context"/>.</summary> /// <summary>The method to call instead of <see cref="System.Threading.ThreadHelper.ThreadStart_Context"/>.</summary>
/// <param name="state">The thread context.</param> /// <param name="state">The thread context.</param>
/// <returns>Returns whether to execute the original method.</returns> /// <returns>Returns whether to execute the original method.</returns>
#if HARMONY_2
private static Exception ThreadStart_Finalizer(Exception __exception) private static Exception ThreadStart_Finalizer(Exception __exception)
{ {
if (__exception != null) { if (__exception != null) {
@ -78,29 +63,6 @@ namespace StardewModdingAPI.Patches
} }
return null; 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 #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 public partial class Resource
{ {
@ -244,97 +244,73 @@ namespace StardewModdingAPI
public static int action_text = 2131034115; public static int action_text = 2131034115;
// aapt resource value: 0x7F050005 // aapt resource value: 0x7F050005
public static int appIcon = 2131034117; public static int async = 2131034117;
// aapt resource value: 0x7F050006 // aapt resource value: 0x7F050006
public static int async = 2131034118; public static int blocking = 2131034118;
// aapt resource value: 0x7F050007 // aapt resource value: 0x7F050007
public static int blocking = 2131034119; public static int chronometer = 2131034119;
// aapt resource value: 0x7F050008 // aapt resource value: 0x7F050008
public static int chronometer = 2131034120; public static int forever = 2131034120;
// aapt resource value: 0x7F050009 // aapt resource value: 0x7F050009
public static int description = 2131034121; public static int icon = 2131034121;
// aapt resource value: 0x7F05000A // aapt resource value: 0x7F05000A
public static int forever = 2131034122; public static int icon_group = 2131034122;
// aapt resource value: 0x7F05000B // aapt resource value: 0x7F05000B
public static int icon = 2131034123; public static int info = 2131034123;
// aapt resource value: 0x7F05000C // aapt resource value: 0x7F05000C
public static int icon_group = 2131034124; public static int italic = 2131034124;
// aapt resource value: 0x7F05000D // aapt resource value: 0x7F05000D
public static int info = 2131034125; public static int line1 = 2131034125;
// aapt resource value: 0x7F05000E // aapt resource value: 0x7F05000E
public static int italic = 2131034126; public static int line3 = 2131034126;
// aapt resource value: 0x7F05000F // aapt resource value: 0x7F05000F
public static int line1 = 2131034127; public static int normal = 2131034127;
// aapt resource value: 0x7F050010 // aapt resource value: 0x7F050010
public static int line3 = 2131034128; public static int notification_background = 2131034128;
// aapt resource value: 0x7F050011 // aapt resource value: 0x7F050011
public static int normal = 2131034129; public static int notification_main_column = 2131034129;
// aapt resource value: 0x7F050012 // aapt resource value: 0x7F050012
public static int notificationLayout = 2131034130; public static int notification_main_column_container = 2131034130;
// aapt resource value: 0x7F050013 // aapt resource value: 0x7F050013
public static int notification_background = 2131034131; public static int right_icon = 2131034131;
// aapt resource value: 0x7F050014 // aapt resource value: 0x7F050014
public static int notification_main_column = 2131034132; public static int right_side = 2131034132;
// aapt resource value: 0x7F050015 // aapt resource value: 0x7F050015
public static int notification_main_column_container = 2131034133; public static int tag_transition_group = 2131034133;
// aapt resource value: 0x7F050016 // aapt resource value: 0x7F050016
public static int progress_bar = 2131034134; public static int tag_unhandled_key_event_manager = 2131034134;
// aapt resource value: 0x7F050017 // aapt resource value: 0x7F050017
public static int progress_bar_frame = 2131034135; public static int tag_unhandled_key_listeners = 2131034135;
// aapt resource value: 0x7F050018 // aapt resource value: 0x7F050018
public static int progress_text = 2131034136; public static int text = 2131034136;
// aapt resource value: 0x7F050019 // aapt resource value: 0x7F050019
public static int right_icon = 2131034137; public static int text2 = 2131034137;
// aapt resource value: 0x7F05001A // aapt resource value: 0x7F05001A
public static int right_side = 2131034138; public static int time = 2131034138;
// aapt resource value: 0x7F05001B // aapt resource value: 0x7F05001B
public static int spacer = 2131034139; public static int title = 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;
static Id() static Id()
{ {
@ -383,9 +359,6 @@ namespace StardewModdingAPI
// aapt resource value: 0x7F070005 // aapt resource value: 0x7F070005
public static int notification_template_part_time = 2131165189; public static int notification_template_part_time = 2131165189;
// aapt resource value: 0x7F070006
public static int status_bar_ongoing_event_progress_bar = 2131165190;
static Layout() static Layout()
{ {
global::Android.Runtime.ResourceIdManager.UpdateIdValues(); global::Android.Runtime.ResourceIdManager.UpdateIdValues();
@ -406,76 +379,7 @@ namespace StardewModdingAPI
public static int hello = 2131230721; public static int hello = 2131230721;
// aapt resource value: 0x7F080002 // aapt resource value: 0x7F080002
public static int kilobytes_per_second = 2131230722; public static int status_bar_notification_info_overflow = 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;
static String() static String()
{ {
@ -491,40 +395,25 @@ namespace StardewModdingAPI
{ {
// aapt resource value: 0x7F090000 // aapt resource value: 0x7F090000
public static int ButtonBackground = 2131296256; public static int TextAppearance_Compat_Notification = 2131296256;
// aapt resource value: 0x7F090001 // aapt resource value: 0x7F090001
public static int NotificationText = 2131296257; public static int TextAppearance_Compat_Notification_Info = 2131296257;
// aapt resource value: 0x7F090002 // aapt resource value: 0x7F090002
public static int NotificationTextSecondary = 2131296258; public static int TextAppearance_Compat_Notification_Line2 = 2131296258;
// aapt resource value: 0x7F090003 // aapt resource value: 0x7F090003
public static int NotificationTextShadow = 2131296259; public static int TextAppearance_Compat_Notification_Time = 2131296259;
// aapt resource value: 0x7F090004 // aapt resource value: 0x7F090004
public static int NotificationTitle = 2131296260; public static int TextAppearance_Compat_Notification_Title = 2131296260;
// aapt resource value: 0x7F090005 // aapt resource value: 0x7F090005
public static int TextAppearance_Compat_Notification = 2131296261; public static int Widget_Compat_NotificationActionContainer = 2131296261;
// aapt resource value: 0x7F090006 // aapt resource value: 0x7F090006
public static int TextAppearance_Compat_Notification_Info = 2131296262; public static int Widget_Compat_NotificationActionText = 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;
static Style() static Style()
{ {

View File

@ -108,10 +108,10 @@ namespace StardewModdingAPI
this.isVisible = false; this.isVisible = false;
Game1.activeClickableMenu = null; Game1.activeClickableMenu = null;
Game1.playSound("bigDeSelect"); Game1.playSound("bigDeSelect");
SMainActivity.Instance.core.CommandQueue.Enqueue(command); SMainActivity.Instance.core.RawCommandQueue.Add(command);
return; 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> <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk> <AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFramework>MonoAndroid</TargetFramework> <TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion> <TargetFramework>net5.0-android</TargetFramework>
<AndroidUseAapt2>true</AndroidUseAapt2> <AndroidUseAapt2>true</AndroidUseAapt2>
<DefineConstants>$(DefineConstants)</DefineConstants> <DefineConstants>$(DefineConstants)</DefineConstants>
</PropertyGroup> </PropertyGroup>
@ -33,7 +33,6 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<LangVersion>8.0</LangVersion>
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis> <AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
</PropertyGroup> </PropertyGroup>
@ -44,7 +43,7 @@
<DefineConstants>$(DefineConstants);TRACE</DefineConstants> <DefineConstants>$(DefineConstants);TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis> <AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode> <AndroidLinkMode>None</AndroidLinkMode>
@ -70,7 +69,7 @@
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup> </PropertyGroup>
<Import Project="..\..\build\common.targets" /> <!-- <Import Project="..\..\build\common.targets" />-->
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''"> <ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''">
<PackageReference Include="LargeAddressAware" Version="1.0.6" /> <PackageReference Include="LargeAddressAware" Version="1.0.6" />
@ -85,7 +84,6 @@
<!-- legacy package; remove in SMAPI 4.0.0 --> <!-- legacy package; remove in SMAPI 4.0.0 -->
<PackageReference Include="System.Runtime.Caching" Version="5.0.0" /> <PackageReference Include="System.Runtime.Caching" Version="5.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''"> <ItemGroup Condition="'$(BUILD_FOR_MOBILE)' == ''">
<Reference Include="..\..\build\0Harmony.dll" Private="True" /> <Reference Include="..\..\build\0Harmony.dll" Private="True" />
<Reference Include="Stardew Valley" HintPath="$(GamePath)\Stardew Valley.dll" Private="False" /> <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)' == ''" /> <Compile Remove="Resources\Resource.designer.cs" Condition="'$(BUILD_FOR_MOBILE)' == ''" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''"> <ItemGroup Condition="$(DefineConstants.Contains('ANDROID_TARGET_GOOGLE'))">
<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'))">
<Reference Include="StardewValley"> <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>
<Reference Include="StardewValley.GameData"> <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>
<Reference Include="xTile"> <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> </Reference>
</ItemGroup> <Reference Include="BmFont">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\BmFont.dll</HintPath>
<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> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''"> <ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''">
<PackageReference Include="MonoGame.Framework.Android">
<Version>3.6.0.862</Version>
</PackageReference>
<Reference Include="MonoGame.Framework"> <Reference Include="MonoGame.Framework">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\MonoGame.Framework.dll</HintPath> <HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.5.6.31\assemblies\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="MonoGame.Framework.Content.Pipeline">
<HintPath>..\..\..\Downloads\StardewValleyAndroidStuff\base_1.4.5.145\assemblies\MonoGame.Framework.Content.Pipeline.dll</HintPath>
</Reference> </Reference>
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />
@ -219,45 +142,39 @@
<Reference Include="0Harmony"> <Reference Include="0Harmony">
<HintPath>..\..\build\0Harmony.dll</HintPath> <HintPath>..\..\build\0Harmony.dll</HintPath>
</Reference> </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="Microsoft.CSharp" />
<Reference Include="SMAPI.Toolkit"> <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>
<Reference Include="SMAPI.Toolkit.CoreInterfaces"> <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>
<Reference Include="TMXTile"> <PackageReference Include="MonoGame.Framework.Android">
<HintPath>..\Loader\libs\TMXTile.dll</HintPath> <Version>3.8.1.303</Version>
</Reference> </PackageReference>
<Reference Include="Microsoft.AppCenter"> <PackageReference Include="SkiaSharp">
<HintPath>..\Loader\libs\Microsoft.AppCenter.dll</HintPath> <Version>2.88.3</Version>
</Reference> </PackageReference>
<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="Xamarin.Android.Support.Compat"> <PackageReference Include="Xamarin.Android.Support.Compat">
<Version>28.0.0.3</Version> <Version>28.0.0.3</Version>
</PackageReference> </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>
<ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''"> <ItemGroup Condition="'$(BUILD_FOR_MOBILE)' != ''">
<Compile Include="**\*.cs" Exclude="**/.vshistory/**;obj/**" /> <Compile Include="**\*.cs" Exclude="**/.vshistory/**;obj/**" />
@ -274,6 +191,10 @@
<Folder Include="Resources\drawable\" /> <Folder Include="Resources\drawable\" />
</ItemGroup> </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="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" Condition="'$(BUILD_FOR_MOBILE)' != ''" />
<Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" /> <Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" />
<Import Project="..\SMAPI.Internal.Patching\SMAPI.Internal.Patching.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.App;
using Android.Support.V4.Content; using Android.Support.V4.Content;
using Android.Views; using Android.Views;
using Google.Android.Vending.Licensing;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
@ -16,9 +15,7 @@ using System.Reflection;
using Java.Interop; using Java.Interop;
using System.Linq; using System.Linq;
using File = Java.IO.File; using File = Java.IO.File;
using Microsoft.AppCenter;
using Newtonsoft.Json; using Newtonsoft.Json;
using Microsoft.AppCenter.Crashes;
using Android.Content; using Android.Content;
using Android.Util; using Android.Util;
using Java.Lang; using Java.Lang;
@ -29,17 +26,9 @@ using Thread = System.Threading.Thread;
namespace StardewModdingAPI 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))] [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 public class SMainActivity: MainActivity
#else
public class SMainActivity : MainActivity, ILicenseCheckerCallback, IJavaObject, IDisposable, IJavaPeerable
#endif
{ {
internal SCore core; internal SCore core;
private LicenseChecker _licenseChecker;
#if ANDROID_TARGET_GOOGLE
private ServerManagedPolicyExtended _serverManagedPolicyExtended;
#endif
public static SMainActivity Instance; public static SMainActivity Instance;
@ -124,10 +113,6 @@ namespace StardewModdingAPI
} }
catch (Exception) { } 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 catch
{ {
@ -164,7 +149,7 @@ namespace StardewModdingAPI
modPath = "StardewValley/Mods"; 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(); this.core.RunInteractively();
typeof(MainActivity).GetField("_game1", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(this, this.core.Game); 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}", SAlertDialogUtil.AlertMessage($"SMAPI failed to initialize: {ex}",
callback: type => callback: type =>
{ {
Crashes.TrackError(ex);
this.Finish(); this.Finish();
}); });
} }
@ -223,49 +207,8 @@ namespace StardewModdingAPI
private void CheckUsingServerManagedPolicy() 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 #endif

View File

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