Merge branch 'develop' into stable

This commit is contained in:
Jesse Plamondon-Willard 2021-12-05 19:10:39 -05:00
commit 8a2618d812
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
44 changed files with 924 additions and 321 deletions

View File

@ -22,6 +22,9 @@ insert_final_newline = false
[README.txt]
end_of_line=crlf
[*.{command,sh}]
end_of_line=lf
##########
## C# formatting
## documentation: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference

5
.gitattributes vendored
View File

@ -1,3 +1,6 @@
# normalize line endings
* text=auto
README.txt text=crlf
README.txt text eol=crlf
*.command text eol=lf
*.sh text eol=lf

View File

@ -1,13 +1,29 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--set general build properties -->
<Version>3.13.1</Version>
<Version>3.13.2</Version>
<Product>SMAPI</Product>
<LangVersion>latest</LangVersion>
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
<!--set platform-->
<DefineConstants Condition="$(OS) == 'Windows_NT'">$(DefineConstants);SMAPI_FOR_WINDOWS</DefineConstants>
<CopyToGameFolder>true</CopyToGameFolder>
<!-- allow mods to be compiled as AnyCPU for compatibility with older platforms -->
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
<!--
suppress warnings that don't apply, so it's easier to spot actual issues.
warning | builds | summary | rationale
┄┄┄┄┄┄┄ | ┄┄┄┄┄┄┄ | ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ | ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
CS0436 | all | local type conflicts with imported type | SMAPI needs to use certain low-level code during very early compatibility checks, before it's safe to load any other DLLs.
CA1416 | all | platform code available on all platforms | Compiler doesn't recognize the #if constants used by SMAPI.
CS0809 | all | obsolete overload for non-onsolete member | This is deliberate to signal to mods that certain APIs are only implemented for the game and shouldn't be called by mods.
NU1701 | all | NuGet package targets older .NET version | All such packages are carefully tested to make sure they do work.
-->
<NoWarn>$(NoWarn);CS0436;CA1416;CS0809;NU1701</NoWarn>
</PropertyGroup>
<!--find game folder-->
@ -19,7 +35,7 @@
</Target>
<!-- copy files into game directory and enable debugging -->
<Target Name="CopySmapiFiles" AfterTargets="AfterBuild">
<Target Name="CopySmapiFiles" AfterTargets="AfterBuild" Condition="'$(CopyToGameFolder)' == 'true'">
<CallTarget Targets="CopySMAPI;CopyDefaultMods" />
</Target>
<Target Name="CopySMAPI" Condition="'$(MSBuildProjectName)' == 'SMAPI'">

View File

@ -1,130 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
This build task is run from the installer project after all projects have been compiled, and
creates the build package in the bin\Packages folder.
-->
<Target Name="PrepareInstaller" AfterTargets="AfterBuild">
<PropertyGroup>
<PlatformName>windows</PlatformName>
<PlatformName Condition="$(OS) != 'Windows_NT'">unix</PlatformName>
<BuildRootPath>$(SolutionDir)</BuildRootPath>
<OutRootPath>$(SolutionDir)\..\bin</OutRootPath>
<SmapiBin>$(BuildRootPath)\SMAPI\bin\$(Configuration)</SmapiBin>
<ToolkitBin>$(BuildRootPath)\SMAPI.Toolkit\bin\$(Configuration)\net5.0</ToolkitBin>
<ConsoleCommandsBin>$(BuildRootPath)\SMAPI.Mods.ConsoleCommands\bin\$(Configuration)</ConsoleCommandsBin>
<ErrorHandlerBin>$(BuildRootPath)\SMAPI.Mods.ErrorHandler\bin\$(Configuration)</ErrorHandlerBin>
<SaveBackupBin>$(BuildRootPath)\SMAPI.Mods.SaveBackup\bin\$(Configuration)</SaveBackupBin>
<PackagePath>$(OutRootPath)\SMAPI installer</PackagePath>
<PackageDevPath>$(OutRootPath)\SMAPI installer for developers</PackageDevPath>
</PropertyGroup>
<ItemGroup>
<TranslationFiles Include="$(SmapiBin)\i18n\*.json" />
<ErrorHandlerTranslationFiles Include="$(ErrorHandlerBin)\i18n\*.json" />
</ItemGroup>
<!-- reset package directory -->
<RemoveDir Directories="$(PackagePath)" />
<RemoveDir Directories="$(PackageDevPath)" />
<!-- copy installer files -->
<Copy SourceFiles="$(TargetDir)\assets\unix-install.sh" DestinationFiles="$(PackagePath)\install on Linux.sh" />
<Copy SourceFiles="$(TargetDir)\assets\unix-install.sh" DestinationFiles="$(PackagePath)\install on macOS.command" />
<Copy SourceFiles="$(TargetDir)\assets\windows-install.bat" DestinationFiles="$(PackagePath)\install on Windows.bat" />
<Copy SourceFiles="$(TargetDir)\assets\README.txt" DestinationFolder="$(PackagePath)" />
<Copy SourceFiles="$(TargetDir)\assets\windows-exe-config.xml" DestinationFiles="$(PackagePath)\internal\$(PlatformName)\install.exe.config" Condition="$(PlatformName) == 'windows'" />
<Copy SourceFiles="$(TargetDir)\$(TargetName).dll" DestinationFolder="$(PackagePath)\internal\$(PlatformName)" />
<Copy SourceFiles="$(TargetDir)\$(TargetName).runtimeconfig.json" DestinationFolder="$(PackagePath)\internal\$(PlatformName)" />
<!--copy bundle files-->
<Copy SourceFiles="$(TargetDir)\assets\runtimeconfig.$(PlatformName).json" DestinationFiles="$(PackagePath)\bundle\StardewModdingAPI.runtimeconfig.json" />
<Copy SourceFiles="$(SmapiBin)\StardewModdingAPI.dll" DestinationFolder="$(PackagePath)\bundle" />
<Copy SourceFiles="$(SmapiBin)\StardewModdingAPI.exe" DestinationFolder="$(PackagePath)\bundle" Condition="$(PlatformName) == 'windows'" />
<Copy SourceFiles="$(SmapiBin)\StardewModdingAPI" DestinationFolder="$(PackagePath)\bundle" Condition="$(PlatformName) != 'windows'" />
<Copy SourceFiles="$(SmapiBin)\StardewModdingAPI.pdb" DestinationFolder="$(PackagePath)\bundle" />
<Copy SourceFiles="$(SmapiBin)\StardewModdingAPI.xml" DestinationFolder="$(PackagePath)\bundle" />
<Copy SourceFiles="$(SmapiBin)\steam_appid.txt" DestinationFolder="$(PackagePath)\bundle" />
<Copy SourceFiles="$(SmapiBin)\0Harmony.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\0Harmony.xml" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\Mono.Cecil.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\Mono.Cecil.Mdb.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\Mono.Cecil.Pdb.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\MonoMod.Common.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\Newtonsoft.Json.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\TMXTile.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\SMAPI.config.json" DestinationFiles="$(PackagePath)\bundle\smapi-internal\config.json" />
<Copy SourceFiles="$(SmapiBin)\SMAPI.metadata.json" DestinationFiles="$(PackagePath)\bundle\smapi-internal\metadata.json" />
<Copy SourceFiles="$(ToolkitBin)\SMAPI.Toolkit.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(ToolkitBin)\SMAPI.Toolkit.pdb" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(ToolkitBin)\SMAPI.Toolkit.xml" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(ToolkitBin)\SMAPI.Toolkit.CoreInterfaces.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(ToolkitBin)\SMAPI.Toolkit.CoreInterfaces.pdb" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(ToolkitBin)\SMAPI.Toolkit.CoreInterfaces.xml" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="@(TranslationFiles)" DestinationFolder="$(PackagePath)\bundle\smapi-internal\i18n" />
<Copy Condition="$(PlatformName) == 'unix'" SourceFiles="$(TargetDir)\assets\unix-launcher.sh" DestinationFolder="$(PackagePath)\bundle" />
<Copy Condition="$(PlatformName) == 'unix'" SourceFiles="$(SmapiBin)\System.Runtime.Caching.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy Condition="$(PlatformName) == 'windows'" SourceFiles="$(TargetDir)\assets\windows-exe-config.xml" DestinationFiles="$(PackagePath)\bundle\StardewModdingAPI.exe.config" />
<!-- copy .NET dependencies -->
<Copy SourceFiles="$(SmapiBin)\System.Configuration.ConfigurationManager.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\System.Management.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" Condition="$(PlatformName) == 'windows'" />
<Copy SourceFiles="$(SmapiBin)\System.Runtime.Caching.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<Copy SourceFiles="$(SmapiBin)\System.Security.Permissions.dll" DestinationFolder="$(PackagePath)\bundle\smapi-internal" />
<!--copy bundled mods-->
<Copy SourceFiles="$(ConsoleCommandsBin)\ConsoleCommands.dll" DestinationFolder="$(PackagePath)\bundle\Mods\ConsoleCommands" />
<Copy SourceFiles="$(ConsoleCommandsBin)\ConsoleCommands.pdb" DestinationFolder="$(PackagePath)\bundle\Mods\ConsoleCommands" />
<Copy SourceFiles="$(ConsoleCommandsBin)\manifest.json" DestinationFolder="$(PackagePath)\bundle\Mods\ConsoleCommands" />
<Copy SourceFiles="$(ErrorHandlerBin)\ErrorHandler.dll" DestinationFolder="$(PackagePath)\bundle\Mods\ErrorHandler" />
<Copy SourceFiles="$(ErrorHandlerBin)\ErrorHandler.pdb" DestinationFolder="$(PackagePath)\bundle\Mods\ErrorHandler" />
<Copy SourceFiles="$(ErrorHandlerBin)\manifest.json" DestinationFolder="$(PackagePath)\bundle\Mods\ErrorHandler" />
<Copy SourceFiles="@(ErrorHandlerTranslationFiles)" DestinationFolder="$(PackagePath)\bundle\Mods\ErrorHandler\i18n" />
<Copy SourceFiles="$(SaveBackupBin)\SaveBackup.dll" DestinationFolder="$(PackagePath)\bundle\Mods\SaveBackup" />
<Copy SourceFiles="$(SaveBackupBin)\SaveBackup.pdb" DestinationFolder="$(PackagePath)\bundle\Mods\SaveBackup" />
<Copy SourceFiles="$(SaveBackupBin)\manifest.json" DestinationFolder="$(PackagePath)\bundle\Mods\SaveBackup" />
<!-- fix Linux/macOS permissions -->
<Exec Condition="$(PlatformName) == 'unix'" Command="chmod 755 &quot;$(PackagePath)/install on Linux.sh&quot;" />
<Exec Condition="$(PlatformName) == 'unix'" Command="chmod 755 &quot;$(PackagePath)/install on macOS.command&quot;" />
<Exec Condition="$(PlatformName) == 'unix'" Command="chmod 755 &quot;$(PackagePath)/bundle/unix-launcher.sh&quot;" />
<!-- finalise 'for developers' installer -->
<ItemGroup>
<PackageFiles Include="$(PackagePath)\**\*.*" />
</ItemGroup>
<Copy SourceFiles="@(PackageFiles)" DestinationFolder="$(PackageDevPath)\%(RecursiveDir)" />
<ZipDirectory SourceDirectory="$(PackageDevPath)\bundle" DestinationFile="$(PackageDevPath)\internal\$(PlatformName)\install.dat" />
<RemoveDir Directories="$(PackageDevPath)\bundle" />
<!-- finalise normal installer -->
<ReplaceFileText FilePath="$(PackagePath)\bundle\smapi-internal\config.json" Search="&quot;DeveloperMode&quot;: true" Replace="&quot;DeveloperMode&quot;: false" />
<ZipDirectory SourceDirectory="$(PackagePath)\bundle" DestinationFile="$(PackagePath)\internal\$(PlatformName)\install.dat" />
<RemoveDir Directories="$(PackagePath)\bundle" />
</Target>
<!-- Replace text in a file based on a regex pattern. Derived from https://stackoverflow.com/a/22571621/262123. -->
<UsingTask TaskName="ReplaceFileText" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<FilePath ParameterType="System.String" Required="true" />
<Search ParameterType="System.String" Required="true" />
<Replace ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Text.RegularExpressions" />
<Code Type="Fragment" Language="cs">
<![CDATA[
File.WriteAllText(
FilePath,
Regex.Replace(File.ReadAllText(FilePath), Search, Replace)
);
]]>
</Code>
</Task>
</UsingTask>
</Project>

View File

@ -0,0 +1,211 @@
#!/bin/bash
#
#
# This is the Bash equivalent of ../windows/prepare-install-package.ps1.
# When making changes, both scripts should be updated.
#
#
##########
## Constants
##########
# paths
gamePath="/home/pathoschild/Stardew Valley"
bundleModNames=("ConsoleCommands" "ErrorHandler" "SaveBackup")
# build configuration
buildConfig="Release"
folders=("linux" "macOS" "windows")
declare -A runtimes=(["linux"]="linux-x64" ["macOS"]="osx-x64" ["windows"]="win-x64")
declare -A msBuildPlatformNames=(["linux"]="Unix" ["macOS"]="OSX" ["windows"]="Windows_NT")
##########
## Move to SMAPI root
##########
cd "`dirname "$0"`/../.."
##########
## Clear old build files
##########
echo "Clearing old builds..."
echo "-------------------------------------------------"
for path in bin */**/bin */**/obj; do
echo "$path"
rm -rf $path
done
echo ""
##########
## Compile files
##########
for folder in ${folders[@]}; do
runtime=${runtimes[$folder]}
msbuildPlatformName=${msBuildPlatformNames[$folder]}
echo "Compiling SMAPI for $folder..."
echo "-------------------------------------------------"
dotnet publish src/SMAPI --configuration $buildConfig -v minimal --runtime "$runtime" -p:OS="$msbuildPlatformName" -p:GamePath="$gamePath" -p:CopyToGameFolder="false" --self-contained true
echo ""
echo ""
echo "Compiling installer for $folder..."
echo "-------------------------------------------------"
dotnet publish src/SMAPI.Installer --configuration $buildConfig -v minimal --runtime "$runtime" -p:OS="$msbuildPlatformName" -p:GamePath="$gamePath" -p:CopyToGameFolder="false" -p:PublishTrimmed=True -p:TrimMode=Link --self-contained true
echo ""
echo ""
for modName in ${bundleModNames[@]}; do
echo "Compiling $modName for $folder..."
echo "-------------------------------------------------"
dotnet publish src/SMAPI.Mods.$modName --configuration $buildConfig -v minimal --runtime "$runtime" -p:OS="$msbuildPlatformName" -p:GamePath="$gamePath" -p:CopyToGameFolder="false"
echo ""
echo ""
done
done
##########
## Prepare install package
##########
echo "Preparing install package..."
echo "-------------------------------------------------"
# init paths
installAssets="src/SMAPI.Installer/assets"
packagePath="bin/SMAPI installer"
packageDevPath="bin/SMAPI installer for developers"
# init structure
for folder in ${folders[@]}; do
mkdir "$packagePath/internal/$folder/bundle/smapi-internal" --parents
done
# copy base installer files
for name in "install on Linux.sh" "install on macOS.command" "install on Windows.bat" "README.txt"; do
cp "$installAssets/$name" "$packagePath"
done
# copy per-platform files
for folder in ${folders[@]}; do
runtime=${runtimes[$folder]}
# get paths
smapiBin="src/SMAPI/bin/$buildConfig/$runtime/publish"
internalPath="$packagePath/internal/$folder"
bundlePath="$internalPath/bundle"
# installer files
cp -r "src/SMAPI.Installer/bin/$buildConfig/$runtime/publish"/* "$internalPath"
rm -rf "$internalPath/assets"
# runtime config for SMAPI
# This is identical to the one generated by the build, except that the min runtime version is
# set to 5.0.0 (instead of whatever version it was built with) and rollForward is set to latestMinor instead of
# minor.
cp "$installAssets/runtimeconfig.json" "$bundlePath/StardewModdingAPI.runtimeconfig.json"
# installer DLL config
if [ $folder == "windows" ]; then
cp "$installAssets/windows-exe-config.xml" "$packagePath/internal/windows/install.exe.config"
fi
# bundle root files
for name in "StardewModdingAPI" "StardewModdingAPI.dll" "StardewModdingAPI.pdb" "StardewModdingAPI.xml" "steam_appid.txt"; do
if [ $name == "StardewModdingAPI" ] && [ $folder == "windows" ]; then
name="$name.exe"
fi
cp "$smapiBin/$name" "$bundlePath"
done
# bundle i18n
cp -r "$smapiBin/i18n" "$bundlePath/smapi-internal"
# bundle smapi-internal
for name in "0Harmony.dll" "0Harmony.xml" "Mono.Cecil.dll" "Mono.Cecil.Mdb.dll" "Mono.Cecil.Pdb.dll" "MonoMod.Common.dll" "Newtonsoft.Json.dll" "TMXTile.dll" "SMAPI.Toolkit.dll" "SMAPI.Toolkit.pdb" "SMAPI.Toolkit.xml" "SMAPI.Toolkit.CoreInterfaces.dll" "SMAPI.Toolkit.CoreInterfaces.pdb" "SMAPI.Toolkit.CoreInterfaces.xml"; do
cp "$smapiBin/$name" "$bundlePath/smapi-internal"
done
cp "$smapiBin/SMAPI.config.json" "$bundlePath/smapi-internal/config.json"
cp "$smapiBin/SMAPI.metadata.json" "$bundlePath/smapi-internal/metadata.json"
if [ $folder == "linux" ] || [ $folder == "macOS" ]; then
cp "$installAssets/unix-launcher.sh" "$bundlePath"
cp "$smapiBin/System.Runtime.Caching.dll" "$bundlePath/smapi-internal"
else
cp "$installAssets/windows-exe-config.xml" "$bundlePath/StardewModdingAPI.exe.config"
fi
# copy .NET dependencies
cp "$smapiBin/System.Configuration.ConfigurationManager.dll" "$bundlePath/smapi-internal"
cp "$smapiBin/System.Runtime.Caching.dll" "$bundlePath/smapi-internal"
cp "$smapiBin/System.Security.Permissions.dll" "$bundlePath/smapi-internal"
if [ $folder == "windows" ]; then
cp "$smapiBin/System.Management.dll" "$bundlePath/smapi-internal"
fi
# copy bundled mods
for modName in ${bundleModNames[@]}; do
fromPath="src/SMAPI.Mods.$modName/bin/$buildConfig/$runtime/publish"
targetPath="$bundlePath/Mods/$modName"
mkdir "$targetPath" --parents
cp "$fromPath/$modName.dll" "$targetPath"
cp "$fromPath/$modName.pdb" "$targetPath"
cp "$fromPath/manifest.json" "$targetPath"
if [ -d "$fromPath/i18n" ]; then
cp -r "$fromPath/i18n" "$targetPath"
fi
done
done
# mark scripts executable
for path in "install on Linux.sh" "install on macOS.command" "bundle/unix-launcher.sh"; do
if [ -f "$packagePath/$path" ]; then
chmod 755 "$packagePath/$path"
fi
done
# split into main + for-dev folders
cp -r "$packagePath" "$packageDevPath"
for folder in ${folders[@]}; do
# disable developer mode in main package
sed --in-place --expression="s/\"DeveloperMode\": true/\"DeveloperMode\": false/" "$packagePath/internal/$folder/bundle/smapi-internal/config.json"
# convert bundle folder into final 'install.dat' files
for path in "$packagePath/internal/$folder" "$packageDevPath/internal/$folder"; do
pushd "$path/bundle" > /dev/null
zip "install.dat" * --recurse-paths --quiet
popd > /dev/null
mv "$path/bundle/install.dat" "$path/install.dat"
rm -rf "$path/bundle"
done
done
##########
## Create release zips
##########
# get version number
version="$1"
if [ $# -eq 0 ]; then
echo "SMAPI release version (like '4.0.0'):"
read version
fi
# rename folders
mv "$packagePath" "bin/SMAPI $version installer"
mv "$packageDevPath" "bin/SMAPI $version installer for developers"
# package files
pushd bin > /dev/null
zip -9 "SMAPI $version installer.zip" "SMAPI $version installer" --recurse-paths --quiet
zip -9 "SMAPI $version installer for developers.zip" "SMAPI $version installer for developers" --recurse-paths --quiet
popd > /dev/null
echo ""
echo "Done! Package created in $(pwd)/bin"

View File

@ -0,0 +1,26 @@
#!/bin/bash
#
#
# This is the Bash equivalent of ../windows/set-smapi-version.ps1.
# When making changes, both scripts should be updated.
#
#
# get version number
version="$1"
if [ $# -eq 0 ]; then
echo "SMAPI release version (like '4.0.0'):"
read version
fi
# move to SMAPI root
cd "`dirname "$0"`/../.."
# apply changes
sed "s/<Version>.+<\/Version>/<Version>$version<\/Version>/" "build/common.targets" --in-place --regexp-extended
sed "s/RawApiVersion = \".+?\";/RawApiVersion = \"$version\";/" "src/SMAPI/Constants.cs" --in-place --regexp-extended
for modName in "ConsoleCommands" "ErrorHandler" "SaveBackup"; do
sed "s/\"(Version|MinimumApiVersion)\": \".+?\"/\"\1\": \"$version\"/g" "src/SMAPI.Mods.$modName/manifest.json" --in-place --regexp-extended
done

View File

@ -0,0 +1,67 @@
#!/bin/bash
##########
## Read config
##########
# get SMAPI version
version="$1"
if [ $# -eq 0 ]; then
echo "SMAPI release version (like '4.0.0'):"
read version
fi
# get Windows bin path
windowsBinPath="$2"
if [ $# -le 1 ]; then
echo "Windows compiled bin path:"
read windowsBinPath
fi
# installer internal folders
buildFolders=("linux" "macOS" "windows")
##########
## Finalize release package
##########
for folderName in "SMAPI $version installer" "SMAPI $version installer for developers"; do
# move files to Linux filesystem
echo "Preparing $folderName.zip..."
echo "-------------------------------------------------"
echo "copying '$windowsBinPath/$folderName' to Linux filesystem..."
cp -r "$windowsBinPath/$folderName" .
# fix permissions
echo "fixing permissions..."
find "$folderName" -type d -exec chmod 755 {} \;
find "$folderName" -type f -exec chmod 644 {} \;
find "$folderName" -name "*.sh" -exec chmod 755 {} \;
find "$folderName" -name "*.command" -exec chmod 755 {} \;
find "$folderName" -name "SMAPI.Installer" -exec chmod 755 {} \;
find "$folderName" -name "StardewModdingAPI" -exec chmod 755 {} \;
# convert bundle folder into final 'install.dat' files
for build in ${buildFolders[@]}; do
echo "packaging $folderName/internal/$build/install.dat..."
pushd "$folderName/internal/$build/bundle" > /dev/null
zip "install.dat" * --recurse-paths --quiet
mv install.dat ../
popd > /dev/null
rm -rf "$folderName/internal/$build/bundle"
done
# zip installer
echo "packaging installer..."
zip -9 "$folderName.zip" "$folderName" --recurse-paths --quiet
# move zip back to Windows bin path
echo "moving release zip to $windowsBinPath/$folderName.zip..."
mv "$folderName.zip" "$windowsBinPath"
rm -rf "$folderName"
echo ""
echo ""
done
echo "Done!"

View File

@ -0,0 +1,11 @@
function In-Place-Regex {
param (
[Parameter(Mandatory)][string]$Path,
[Parameter(Mandatory)][string]$Search,
[Parameter(Mandatory)][string]$Replace
)
$content = (Get-Content "$Path" -Encoding UTF8)
$content = ($content -replace "$Search", "$Replace")
[System.IO.File]::WriteAllLines((Get-Item "$Path").FullName, $content)
}

View File

@ -0,0 +1,217 @@
#
#
# This is the PowerShell equivalent of ../unix/prepare-install-package.sh, *except* that it doesn't
# set Linux permissions, create the install.dat files, or create the final zip. Due to limitations
# in PowerShell, the final changes are handled by the windows/finalize-install-package.sh file in
# WSL.
#
# When making changes, make sure to update ../unix/prepare-install-package.ps1 too.
#
#
. "$PSScriptRoot\lib\in-place-regex.ps1"
##########
## Constants
##########
# paths
$gamePath = "C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley"
$bundleModNames = "ConsoleCommands", "ErrorHandler", "SaveBackup"
# build configuration
$buildConfig = "Release"
$folders = "linux", "macOS", "windows"
$runtimes = @{ linux = "linux-x64"; macOS = "osx-x64"; windows = "win-x64" }
$msBuildPlatformNames = @{ linux = "Unix"; macOS = "OSX"; windows = "Windows_NT" }
##########
## Move to SMAPI root
##########
cd "$PSScriptRoot/../.."
##########
## Clear old build files
##########
echo "Clearing old builds..."
echo "-------------------------------------------------"
foreach ($path in (dir -Recurse -Include ('bin', 'obj'))) {
echo "$path"
rm -Recurse -Force "$path"
}
echo ""
##########
## Compile files
##########
ForEach ($folder in $folders) {
$runtime = $runtimes[$folder]
$msbuildPlatformName = $msBuildPlatformNames[$folder]
echo "Compiling SMAPI for $folder..."
echo "-------------------------------------------------"
dotnet publish src/SMAPI --configuration $buildConfig -v minimal --runtime "$runtime" -p:OS="$msbuildPlatformName" -p:GamePath="$gamePath" -p:CopyToGameFolder="false" --self-contained true
echo ""
echo ""
echo "Compiling installer for $folder..."
echo "-------------------------------------------------"
dotnet publish src/SMAPI.Installer --configuration $buildConfig -v minimal --runtime "$runtime" -p:OS="$msbuildPlatformName" -p:GamePath="$gamePath" -p:CopyToGameFolder="false" -p:PublishTrimmed=True -p:TrimMode=Link --self-contained true
echo ""
echo ""
foreach ($modName in $bundleModNames) {
echo "Compiling $modName for $folder..."
echo "-------------------------------------------------"
dotnet publish src/SMAPI.Mods.$modName --configuration $buildConfig -v minimal --runtime "$runtime" -p:OS="$msbuildPlatformName" -p:GamePath="$gamePath" -p:CopyToGameFolder="false"
echo ""
echo ""
}
}
##########
## Prepare install package
##########
echo "Preparing install package..."
echo "----------------------------"
# init paths
$installAssets = "src/SMAPI.Installer/assets"
$packagePath = "bin/SMAPI installer"
$packageDevPath = "bin/SMAPI installer for developers"
# init structure
foreach ($folder in $folders) {
mkdir "$packagePath/internal/$folder/bundle/smapi-internal" > $null
}
# copy base installer files
foreach ($name in @("install on Linux.sh", "install on macOS.command", "install on Windows.bat", "README.txt")) {
cp "$installAssets/$name" "$packagePath"
}
# copy per-platform files
foreach ($folder in $folders) {
$runtime = $runtimes[$folder]
# get paths
$smapiBin = "src/SMAPI/bin/$buildConfig/$runtime/publish"
$internalPath = "$packagePath/internal/$folder"
$bundlePath = "$internalPath/bundle"
# installer files
cp "src/SMAPI.Installer/bin/$buildConfig/$runtime/publish/*" "$internalPath" -Recurse
rm -Recurse -Force "$internalPath/assets"
# runtime config for SMAPI
# This is identical to the one generated by the build, except that the min runtime version is
# set to 5.0.0 (instead of whatever version it was built with) and rollForward is set to latestMinor instead of
# minor.
cp "$installAssets/runtimeconfig.json" "$bundlePath/StardewModdingAPI.runtimeconfig.json"
# installer DLL config
if ($folder -eq "windows") {
cp "$installAssets/windows-exe-config.xml" "$packagePath/internal/windows/install.exe.config"
}
# bundle root files
foreach ($name in @("StardewModdingAPI", "StardewModdingAPI.dll", "StardewModdingAPI.pdb", "StardewModdingAPI.xml", "steam_appid.txt")) {
if ($name -eq "StardewModdingAPI" -and $folder -eq "windows") {
$name = "$name.exe"
}
cp "$smapiBin/$name" "$bundlePath"
}
# bundle i18n
cp -Recurse "$smapiBin/i18n" "$bundlePath/smapi-internal"
# bundle smapi-internal
foreach ($name in @("0Harmony.dll", "0Harmony.xml", "Mono.Cecil.dll", "Mono.Cecil.Mdb.dll", "Mono.Cecil.Pdb.dll", "MonoMod.Common.dll", "Newtonsoft.Json.dll", "TMXTile.dll", "SMAPI.Toolkit.dll", "SMAPI.Toolkit.pdb", "SMAPI.Toolkit.xml", "SMAPI.Toolkit.CoreInterfaces.dll", "SMAPI.Toolkit.CoreInterfaces.pdb", "SMAPI.Toolkit.CoreInterfaces.xml")) {
cp "$smapiBin/$name" "$bundlePath/smapi-internal"
}
cp "$smapiBin/SMAPI.config.json" "$bundlePath/smapi-internal/config.json"
cp "$smapiBin/SMAPI.metadata.json" "$bundlePath/smapi-internal/metadata.json"
if ($folder -eq "linux" -or $folder -eq "macOS") {
cp "$installAssets/unix-launcher.sh" "$bundlePath"
cp "$smapiBin/System.Runtime.Caching.dll" "$bundlePath/smapi-internal"
}
else {
cp "$installAssets/windows-exe-config.xml" "$bundlePath/StardewModdingAPI.exe.config"
}
# copy .NET dependencies
cp "$smapiBin/System.Configuration.ConfigurationManager.dll" "$bundlePath/smapi-internal"
cp "$smapiBin/System.Runtime.Caching.dll" "$bundlePath/smapi-internal"
cp "$smapiBin/System.Security.Permissions.dll" "$bundlePath/smapi-internal"
if ($folder -eq "windows") {
cp "$smapiBin/System.Management.dll" "$bundlePath/smapi-internal"
}
# copy bundled mods
foreach ($modName in $bundleModNames) {
$fromPath = "src/SMAPI.Mods.$modName/bin/$buildConfig/$runtime/publish"
$targetPath = "$bundlePath/Mods/$modName"
mkdir "$targetPath" > $null
cp "$fromPath/$modName.dll" "$targetPath"
cp "$fromPath/$modName.pdb" "$targetPath"
cp "$fromPath/manifest.json" "$targetPath"
if (Test-Path "$fromPath/i18n" -PathType Container) {
cp -Recurse "$fromPath/i18n" "$targetPath"
}
}
}
# DISABLED: will be handled by Linux script
# mark scripts executable
#ForEach ($path in @("install on Linux.sh", "install on macOS.command", "bundle/unix-launcher.sh")) {
# if (Test-Path "$packagePath/$path" -PathType Leaf) {
# chmod 755 "$packagePath/$path"
# }
#}
# split into main + for-dev folders
cp -Recurse "$packagePath" "$packageDevPath"
foreach ($folder in $folders) {
# disable developer mode in main package
In-Place-Regex -Path "$packagePath/internal/$folder/bundle/smapi-internal/config.json" -Search "`"DeveloperMode`": true" -Replace "`"DeveloperMode`": false"
# DISABLED: will be handled by Linux script
# convert bundle folder into final 'install.dat' files
#foreach ($path in @("$packagePath/internal/$folder", "$packageDevPath/internal/$folder"))
#{
# Compress-Archive -Path "$path/bundle/*" -CompressionLevel Optimal -DestinationPath "$path/install.zip"
# mv "$path/install.zip" "$path/install.dat"
# rm -Recurse -Force "$path/bundle"
#}
}
###########
### Create release zips
###########
# get version number
$version = $args[0]
if (!$version) {
$version = Read-Host "SMAPI release version (like '4.0.0')"
}
# rename folders
mv "$packagePath" "bin/SMAPI $version installer"
mv "$packageDevPath" "bin/SMAPI $version installer for developers"
# DISABLED: will be handled by Linux script
## package files
#Compress-Archive -Path "bin/SMAPI $version installer" -DestinationPath "bin/SMAPI $version installer.zip" -CompressionLevel Optimal
#Compress-Archive -Path "bin/SMAPI $version installer for developers" -DestinationPath "bin/SMAPI $version installer for developers.zip" -CompressionLevel Optimal
echo ""
echo "Done! See docs/technical/smapi.md to create the release zips."

View File

@ -0,0 +1,25 @@
#
#
# This is the PowerShell equivalent of ../unix/set-smapi-version.sh.
# When making changes, both scripts should be updated.
#
#
. "$PSScriptRoot\lib\in-place-regex.ps1"
# get version number
$version=$args[0]
if (!$version) {
$version = Read-Host "SMAPI release version (like '4.0.0')"
}
# move to SMAPI root
cd "$PSScriptRoot/../.."
# apply changes
In-Place-Regex -Path "build/common.targets" -Search "<Version>.+</Version>" -Replace "<Version>$version</Version>"
In-Place-Regex -Path "src/SMAPI/Constants.cs" -Search "RawApiVersion = `".+?`";" -Replace "RawApiVersion = `"$version`";"
ForEach ($modName in "ConsoleCommands","ErrorHandler","SaveBackup") {
In-Place-Regex -Path "src/SMAPI.Mods.$modName/manifest.json" -Search "`"(Version|MinimumApiVersion)`": `".+?`"" -Replace "`"`$1`": `"$version`""
}

View File

@ -1,11 +1,27 @@
← [README](README.md)
# Release notes
## 3.13.2
Released 05 December 2021 for Stardew Valley 1.5.5 or later.
* For players:
* You no longer need .NET 5 to install or use SMAPI.
* The installer now detects when the game folder contains an incompatible legacy game version.
* Updated for the latest Stardew Valley 1.5.5 hotfix.
* Updated compatibility list.
* For the web UI:
* Fixed the JSON validator marking `.fnt` files invalid in Content Patcher files.
* For SMAPI maintainers:
* Added [release package scripts](technical/smapi.md) to streamline preparing SMAPI releases.
## 3.13.1
Released 30 November 2021 for Stardew Valley 1.5.5 or later.
* Improved .NET 5 validation in Windows installer to better explain how to get the right version.
* Fixed installer failing on Windows when run from the game folder.
* For players:
* Improved .NET 5 validation in Windows installer to better explain how to get the right version.
* Fixed installer failing on Windows when run from the game folder.
## 3.13.0
Released 30 November 2021 for Stardew Valley 1.5.5 or later.

View File

@ -412,7 +412,9 @@ The NuGet package is generated automatically in `StardewModdingAPI.ModBuildConfi
when you compile it.
## Release notes
## Upcoming release
## 4.0.0
Released 30 November 2021.
* Updated for Stardew Valley 1.5.5 and SMAPI 3.13.0. (Older versions are no longer supported.)
* Added `IgnoreModFilePaths` option to ignore literal paths.
* Added `BundleExtraAssemblies` option to copy bundled DLLs into the mod zip/folder.

View File

@ -11,11 +11,12 @@ This document is about SMAPI itself; see also [mod build package](mod-package.md
* [Configuration file](#configuration-file)
* [Command-line arguments](#command-line-arguments)
* [Compile flags](#compile-flags)
* [For SMAPI developers](#for-smapi-developers)
* [Compiling from source](#compiling-from-source)
* [Debugging a local build](#debugging-a-local-build)
* [Preparing a release](#preparing-a-release)
* [Using a custom Harmony build](#using-a-custom-harmony-build)
* [Compile from source code](#compile-from-source-code)
* [Main project](#main-project)
* [Custom Harmony build](#custom-harmony-build)
* [Prepare a release](#prepare-a-release)
* [On any platform](#on-any-platform)
* [On Windows](#on-windows)
* [Release notes](#release-notes)
## Customisation
@ -58,39 +59,42 @@ flag | purpose
---- | -------
`SMAPI_FOR_WINDOWS` | Whether SMAPI is being compiled for Windows; if not set, the code assumes Linux/macOS. Set automatically in `common.targets`.
## For SMAPI developers
### Compiling from source
## Compile from source code
### Main project
Using an official SMAPI release is recommended for most users, but you can compile from source
directly if needed. There are no special steps (just open the project and compile), but SMAPI often
uses the latest C# syntax. You may need the latest version of your IDE to compile it.
directly if needed. Just open the project in an IDE like [Visual
Studio](https://visualstudio.microsoft.com/vs/community/) or [Rider](https://www.jetbrains.com/rider/),
and build the `SMAPI` project. The project will automatically adjust the build settings for your
current OS and Stardew Valley install path.
SMAPI uses build configuration derived from the [crossplatform mod config](https://smapi.io/package/readme)
to detect your current OS automatically and load the correct references. Compile output will be
placed in a `bin` folder at the root of the Git repository.
### Debugging a local build
Rebuilding the solution in debug mode will copy the SMAPI files into your game folder. Starting
the `SMAPI` project with debugging from Visual Studio (on macOS or Windows) will launch SMAPI with
the debugger attached, so you can intercept errors and step through the code being executed. That
doesn't work in MonoDevelop on Linux, unfortunately.
the `SMAPI` project with debugging from Visual Studio or Rider should launch SMAPI with the
debugger attached, so you can intercept errors and step through the code being executed.
### Preparing a release
To prepare a crossplatform SMAPI release, you'll need to compile it on two platforms: Windows and
Linux. The instructions below assume you have Windows 11, but you can adapt them for
a different setup if needed.
### Custom Harmony build
SMAPI uses [a custom build of Harmony](https://github.com/Pathoschild/Harmony#readme), which is
included in the `build` folder. To use a different build, just replace `0Harmony.dll` in that
folder before compiling.
#### Initial setup
First-time setup on Windows:
1. [Install Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install).
2. Install the needed software in WSL:
1. Run `sudo apt update` to update the package list.
2. Install [the .NET 5 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu)
(for Stardew Valley 1.5.5+) or [`mono-complete`](https://www.mono-project.com/download/stable/)
(for earlier versions).
_You can run `lsb_release -a` to get the Ubuntu version number._
3. [Install Steam](https://linuxconfig.org/how-to-install-steam-on-ubuntu-20-04-focal-fossa-linux).
4. Launch `steam` and install the game like usual.
5. Download and install your preferred IDE. For the [latest standalone Rider
## Prepare a release
### On any platform
**⚠ Ideally we'd have one set of instructions for all platforms. The instructions in this section
will produce a fully functional release for all supported platfrms, _except_ that the application
icon for SMAPI on Windows will disappear due to [.NET runtime bug
3828](https://github.com/dotnet/runtime/issues/3828). Until that's fixed, see the _[on
Windows](#on-windows)_ section below to create a build that retains the icon.**
#### First-time setup
1. On Windows only:
1. [Install Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install).
2. Run `sudo apt update` in WSL to update the package list.
3. The rest of the instructions below should be run in WSL.
2. Install the required software:
1. Install the [.NET 5 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu).
_For Ubuntu-based systems, you can run `lsb_release -a` to get the Ubuntu version number._
2. [Install Steam](https://linuxconfig.org/how-to-install-steam-on-ubuntu-20-04-focal-fossa-linux).
3. Launch `steam` and install the game like usual.
4. Download and install your preferred IDE. For the [latest standalone Rider
version](https://www.jetbrains.com/help/rider/Installation_guide.html#prerequisites):
```sh
wget "<download url here>" -O rider-install.tar.gz
@ -98,47 +102,67 @@ First-time setup on Windows:
ln -s "/opt/JetBrains Rider-<version>/bin/rider.sh"
./rider.sh
```
3. Clone the SMAPI repo in WSL:
```sh
git clone https://github.com/Pathoschild/SMAPI.git
```
3. Clone the SMAPI repo:
```sh
git clone https://github.com/Pathoschild/SMAPI.git
```
To compile SMAPI in WSL:
1. Run `./rider.sh` to open the Rider GUI.
2. Use the GUI to compile the solution.
To launch the game:
1. Open a WSL terminal.
2. Run these commands to start Steam:
### Launch the game
1. Run these commands to start Steam:
```sh
export TERM=xterm
steam
```
3. Launch the game through the Steam UI.
2. Launch the game through the Steam UI.
#### Prepare the release
1. Update the version numbers in `build/common.targets`, `Constants`, and the `manifest.json` for
bundled mods. Make sure you use a [semantic version](https://semver.org). Recommended format:
### Prepare the release
1. Run `build/unix/set-smapi-version.sh` to set the SMAPI version. Make sure you use a [semantic
version](https://semver.org). Recommended format:
build type | format | example
:--------- | :----------------------- | :------
dev build | `<version>-alpha.<date>` | `3.0.0-alpha.20171230`
prerelease | `<version>-beta.<date>` | `3.0.0-beta.20171230`
release | `<version>` | `3.0.0`
2. In Windows:
1. Rebuild the solution with the _release_ solution configuration.
2. Copy the `bin/SMAPI installer` and `bin/SMAPI installer for developers` folders to Linux.
4. In Linux:
1. Rebuild the solution with the _release_ solution configuration.
2. Add the `windows-install.*` files from Windows to the `bin/SMAPI installer` and
`bin/SMAPI installer for developers` folders compiled on Linux.
3. Rename the folders to `SMAPI <version> installer` and `SMAPI <version> installer for developers`.
4. Zip the two folders.
dev build | `<version>-alpha.<date>` | `4.0.0-alpha.20251230`
prerelease | `<version>-beta.<date>` | `4.0.0-beta.20251230`
release | `<version>` | `4.0.0`
### Custom Harmony build
SMAPI uses [a custom build of Harmony](https://github.com/Pathoschild/Harmony#readme), which is
included in the `build` folder. To use a different build, just replace `0Harmony.dll` in that
folder before compiling.
2. Run `build/unix/prepare-install-package.sh` to create the release package in the root `bin`
folder.
### On Windows
#### First-time setup
1. Set up Windows Subsystem for Linux (WSL):
1. [Install WSL](https://docs.microsoft.com/en-us/windows/wsl/install).
2. Run `sudo apt update` in WSL to update the package list.
3. The rest of the instructions below should be run in WSL.
2. Install the required software:
1. Install the [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0).
2. Install [Stardew Valley](https://www.stardewvalley.net/).
3. Clone the SMAPI repo:
```sh
git clone https://github.com/Pathoschild/SMAPI.git
```
### Prepare the release
1. Run `build/windows/set-smapi-version.ps1` in PowerShell to set the SMAPI version. Make sure you
use a [semantic version](https://semver.org). Recommended format:
build type | format | example
:--------- | :----------------------- | :------
dev build | `<version>-alpha.<date>` | `4.0.0-alpha.20251230`
prerelease | `<version>-beta.<date>` | `4.0.0-beta.20251230`
release | `<version>` | `4.0.0`
2. Run `build/windows/prepare-install-package.ps1` in PowerShell to create the release package
folders in the root `bin` folder.
3. Launch WSL and run this script:
```bash
# edit to match the build created in steps 1-2
# In WSL, `/mnt/c/example` accesses `C:\example` on the Windows filesystem.
version="4.0.0"
binFolder="/mnt/e/source/_Stardew/SMAPI/bin"
build/windows/finalize-install-package.sh "$version" "$binFolder"
```
## Release notes
See [release notes](../release-notes.md).

View File

@ -54,5 +54,12 @@ namespace StardewModdingAPI.Installer.Framework
{
return this.GameScanner.LooksLikeGameFolder(dir);
}
/// <summary>Get whether a folder seems to contain the game, and which version it contains if so.</summary>
/// <param name="dir">The folder to check.</param>
public GameFolderType GetGameFolderType(DirectoryInfo dir)
{
return this.GameScanner.GetGameFolderType(dir);
}
}
}

View File

@ -10,6 +10,7 @@ using StardewModdingAPI.Installer.Framework;
using StardewModdingAPI.Internal.ConsoleWriting;
using StardewModdingAPI.Toolkit;
using StardewModdingAPI.Toolkit.Framework;
using StardewModdingAPI.Toolkit.Framework.GameScanning;
using StardewModdingAPI.Toolkit.Framework.ModScanning;
using StardewModdingAPI.Toolkit.Utilities;
@ -633,18 +634,39 @@ namespace StardewModdingApi.Installer
// use specified path
if (specifiedPath != null)
{
string errorPrefix = $"You specified --game-path \"{specifiedPath}\", but";
var dir = new DirectoryInfo(specifiedPath);
if (!dir.Exists)
{
this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't exist.");
this.PrintError($"{errorPrefix} that folder doesn't exist.");
return null;
}
if (!context.LooksLikeGameFolder(dir))
switch (context.GetGameFolderType(dir))
{
this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't contain the Stardew Valley executable.");
return null;
case GameFolderType.Valid:
return dir;
case GameFolderType.Legacy154OrEarlier:
this.PrintWarning($"{errorPrefix} that directory seems to have Stardew Valley 1.5.4 or earlier.");
this.PrintWarning("Please update your game to the latest version to use SMAPI.");
return null;
case GameFolderType.LegacyCompatibilityBranch:
this.PrintWarning($"{errorPrefix} that directory seems to have the Stardew Valley legacy 'compatibility' branch.");
this.PrintWarning("Unfortunately SMAPI is only compatible with the modern version of the game.");
this.PrintWarning("Please update your game to the main branch to use SMAPI.");
return null;
case GameFolderType.NoGameFound:
this.PrintWarning($"{errorPrefix} that directory doesn't contain a Stardew Valley executable.");
return null;
default:
this.PrintWarning($"{errorPrefix} that directory doesn't seem to contain a valid game install.");
return null;
}
return dir;
}
// let user choose detected path
@ -702,15 +724,32 @@ namespace StardewModdingApi.Installer
this.PrintWarning("That directory doesn't seem to exist.");
continue;
}
if (!context.LooksLikeGameFolder(directory))
{
this.PrintWarning("That directory doesn't contain a Stardew Valley executable.");
continue;
}
// looks OK
this.PrintInfo(" OK!");
return directory;
switch (context.GetGameFolderType(directory))
{
case GameFolderType.Valid:
this.PrintInfo(" OK!");
return directory;
case GameFolderType.Legacy154OrEarlier:
this.PrintWarning("That directory seems to have Stardew Valley 1.5.4 or earlier.");
this.PrintWarning("Please update your game to the latest version to use SMAPI.");
continue;
case GameFolderType.LegacyCompatibilityBranch:
this.PrintWarning("That directory seems to have the Stardew Valley legacy 'compatibility' branch.");
this.PrintWarning("Unfortunately SMAPI is only compatible with the modern version of the game.");
this.PrintWarning("Please update your game to the main branch to use SMAPI.");
continue;
case GameFolderType.NoGameFound:
this.PrintWarning("That directory doesn't contain a Stardew Valley executable.");
continue;
default:
this.PrintWarning("That directory doesn't seem to contain a valid game install.");
continue;
}
}
}

View File

@ -17,5 +17,4 @@
<Import Project="..\SMAPI.Internal\SMAPI.Internal.projitems" Label="Shared" />
<Import Project="..\..\build\common.targets" />
<Import Project="..\..\build\prepare-install-package.targets" />
</Project>

View File

@ -14,22 +14,27 @@
SMAPI lets you run Stardew Valley with mods. Don't forget to download mods separately.
Player's guide
Automated install
--------------------------------
See https://stardewvalleywiki.com/Modding:Player_Guide for help installing SMAPI, adding mods, etc.
Manual install
--------------------------------
THIS IS NOT RECOMMENDED FOR MOST PLAYERS. See instructions above instead.
THIS IS NOT RECOMMENDED FOR MOST PLAYERS. See the instructions above instead.
If you really want to install SMAPI manually, here's how.
1. Unzip "internal/windows/install.dat" (on Windows) or "internal/unix/install.dat" (on
Linux/macOS). You can change '.dat' to '.zip', it's just a normal zip file renamed to prevent
1. Unzip "internal/windows/install.dat" (on Windows) or "internal/unix/install.dat" (on Linux or
macOS). You can change '.dat' to '.zip', it's just a normal zip file renamed to prevent
confusion.
2. Copy the files from the folder you just unzipped into your game folder. The
`StardewModdingAPI.exe` file should be right next to the game's executable.
3.
3. Copy `Stardew Valley.deps.json` in the game folder, and rename the copy to
`StardewModdingAPI.deps.json`.
4.
- Windows only: if you use Steam, see the install guide above to enable achievements and
overlay. Otherwise, just run StardewModdingAPI.exe in your game folder to play with mods.
@ -38,8 +43,5 @@ If you really want to install SMAPI manually, here's how.
play with mods.
When installing on Linux or macOS:
- Make sure Mono is installed (normally the installer checks for you). While it's not required,
many mods won't work correctly without it. (Specifically, mods which load PNG images may crash or
freeze the game.)
- To configure the color scheme, edit the `smapi-internal/config.json` file and see instructions
there for the 'ColorScheme' setting.

View File

@ -0,0 +1,4 @@
#!/bin/bash
cd "`dirname "$0"`"
internal/linux/SMAPI.Installer

View File

@ -12,36 +12,6 @@ if %ERRORLEVEL% EQU 0 (
exit
)
REM make sure .NET 5 is installed
SET hasNet5=1
WHERE dotnet /q
if !ERRORLEVEL! NEQ 0 (
SET hasNet5=0
) else (
dotnet --info | findstr /C:"Microsoft.WindowsDesktop.App 5." 1>nul
if !ERRORLEVEL! NEQ 0 (
SET hasNet5=0
)
)
if "%hasNet5%" == "0" (
echo Oops! You don't have the required .NET version installed.
echo.
echo To install it:
echo 1. Go to https://dotnet.microsoft.com/download/dotnet/5.0/runtime
if "%PROCESSOR_ARCHITECTURE%" == "ARM64" (
echo 2. Under "Run desktop apps", click "Download Arm64".
) else (
echo 2. Under "Run desktop apps", click "Download x64".
)
echo 3. Run the downloaded installer.
echo 4. Restart your computer.
echo.
pause
exit
)
REM make sure an antivirus hasn't deleted the installer DLL
if not exist %installerDir%"internal\windows\SMAPI.Installer.dll" (
echo Oops! SMAPI is missing one of its files. Your antivirus might have deleted it.
@ -50,9 +20,16 @@ if not exist %installerDir%"internal\windows\SMAPI.Installer.dll" (
pause
exit
)
if not exist %installerDir%"internal\windows\SMAPI.Installer.exe" (
echo Oops! SMAPI is missing one of its files. Your antivirus might have deleted it.
echo Missing file: %installerDir%internal\windows\SMAPI.Installer.exe
echo.
pause
exit
)
REM start installer
dotnet internal\windows\SMAPI.Installer.dll
internal\windows\SMAPI.Installer.exe
REM keep window open if it failed
if %ERRORLEVEL% NEQ 0 (

View File

@ -0,0 +1,6 @@
#!/bin/bash
cd "`dirname "$0"`"
xattr -r -d com.apple.quarantine internal
internal/macOS/SMAPI.Installer

View File

@ -4,11 +4,13 @@
"includedFrameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "5.0.7"
"version": "5.0.0",
"rollForward": "latestMinor"
}
],
"configProperties": {
"System.Runtime.TieredCompilation": false
"System.Runtime.TieredCompilation": false,
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false
}
}
}

View File

@ -1,12 +0,0 @@
{
"runtimeOptions": {
"tfm": "net5.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "5.0.0"
},
"configProperties": {
"System.Runtime.TieredCompilation": false
}
}
}

View File

@ -1,14 +0,0 @@
#!/bin/bash
# Move to script's directory
cd "`dirname "$0"`"
# make sure .NET 5 is installed
if ! command -v dotnet >/dev/null 2>&1; then
echo "Oops! You must have .NET 5 installed to use SMAPI: https://dotnet.microsoft.com/download";
read
exit 1
fi
# run installer
dotnet internal/unix/SMAPI.Installer.dll

View File

@ -49,20 +49,13 @@ if [ ! -f "Stardew Valley.dll" ]; then
exit 1
fi
# .NET 5 must be installed
if ! command -v dotnet >/dev/null 2>&1; then
echo "Oops! You must have .NET 5 installed to use SMAPI: https://dotnet.microsoft.com/download";
read
exit 1
fi
##########
## Launch SMAPI
##########
# macOS
if [ "$(uname)" == "Darwin" ]; then
dotnet StardewModdingAPI.dll "$@"
./StardewModdingAPI "$@"
# Linux
else

View File

@ -315,7 +315,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer
return false;
// conversion to implemented interface is OK
if (fromType.AllInterfaces.Contains(toType))
if (fromType.AllInterfaces.Contains(toType, SymbolEqualityComparer.Default))
return false;
// avoid any other conversions

View File

@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
"Version": "3.13.1",
"Version": "3.13.2",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
"MinimumApiVersion": "3.13.1"
"MinimumApiVersion": "3.13.2"
}

View File

@ -1,4 +1,4 @@
{
// warning messages
"warn.invalid-content-removed": "Nieprawidłowa zawartość została usunięta, aby zapobiec awarii (zobacz konsolę SMAPI po więcej informacji)."
}
{
// warning messages
"warn.invalid-content-removed": "Nieprawidłowa zawartość została usunięta, aby zapobiec awarii (zobacz konsolę SMAPI po więcej informacji)."
}

View File

@ -1,9 +1,9 @@
{
"Name": "Error Handler",
"Author": "SMAPI",
"Version": "3.13.1",
"Version": "3.13.2",
"Description": "Handles some common vanilla errors to log more useful info or avoid breaking the game.",
"UniqueID": "SMAPI.ErrorHandler",
"EntryDll": "ErrorHandler.dll",
"MinimumApiVersion": "3.13.1"
"MinimumApiVersion": "3.13.2"
}

View File

@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
"Version": "3.13.1",
"Version": "3.13.2",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
"MinimumApiVersion": "3.13.1"
"MinimumApiVersion": "3.13.2"
}

View File

@ -0,0 +1,21 @@
namespace StardewModdingAPI.Toolkit.Framework.GameScanning
{
/// <summary>The detected validity for a Stardew Valley game folder based on file structure heuristics.</summary>
public enum GameFolderType
{
/// <summary>The folder seems to contain a valid Stardew Valley 1.5.5+ install.</summary>
Valid,
/// <summary>The folder doesn't contain Stardew Valley.</summary>
NoGameFound,
/// <summary>The folder contains Stardew Valley 1.5.4 or earlier. This version uses XNA Framework and 32-bit .NET Framework 4.5.2 on Windows and Mono on Linux/macOS, and isn't compatible with current versions of SMAPI.</summary>
Legacy154OrEarlier,
/// <summary>The folder contains Stardew Valley from the game's legacy compatibility branch, which backports newer changes to the <see cref="Legacy154OrEarlier"/> format.</summary>
LegacyCompatibilityBranch,
/// <summary>The folder seems to contain Stardew Valley files, but they failed to load for unknown reasons (e.g. corrupted executable).</summary>
InvalidUnknown
}
}

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using StardewModdingAPI.Toolkit.Utilities;
using System.Reflection;
#if SMAPI_FOR_WINDOWS
using Microsoft.Win32;
#endif
@ -54,11 +55,59 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
/// <param name="dir">The folder to check.</param>
public bool LooksLikeGameFolder(DirectoryInfo dir)
{
return
dir.Exists
&& dir.EnumerateFiles("Stardew Valley.dll").Any();
return this.GetGameFolderType(dir) == GameFolderType.Valid;
}
/// <summary>Detect the validity of a game folder based on file structure heuristics.</summary>
/// <param name="dir">The folder to check.</param>
public GameFolderType GetGameFolderType(DirectoryInfo dir)
{
// no such folder
if (!dir.Exists)
return GameFolderType.NoGameFound;
// apparently valid
if (dir.EnumerateFiles("Stardew Valley.dll").Any())
return GameFolderType.Valid;
// doesn't contain any version of Stardew Valley
FileInfo executable = new(Path.Combine(dir.FullName, "Stardew Valley.exe"));
if (!executable.Exists)
executable = new(Path.Combine(dir.FullName, "StardewValley.exe")); // pre-1.5.5 Linux/macOS executable
if (!executable.Exists)
return GameFolderType.NoGameFound;
// get assembly version
Version version;
try
{
version = AssemblyName.GetAssemblyName(executable.FullName).Version;
}
catch
{
// The executable exists but it doesn't seem to be a valid assembly. This would
// happen with Stardew Valley 1.5.5+, but that should have been flagged as a valid
// folder before this point.
return GameFolderType.InvalidUnknown;
}
// ignore Stardew Valley 1.5.5+ at this point
if (version.Major == 1 && version.Minor == 3 && version.Build == 37)
return GameFolderType.InvalidUnknown;
// incompatible version
if (version.Major == 1 && version.Minor < 4)
{
// Stardew Valley 1.5.4 and earlier have assembly versions <= 1.3.7853.31734
if (version.Minor < 3 || version.Build <= 7853)
return GameFolderType.Legacy154OrEarlier;
// Stardew Valley 1.5.5+ legacy compatibility branch
return GameFolderType.LegacyCompatibilityBranch;
}
return GameFolderType.InvalidUnknown;
}
/*********
** Private methods

View File

@ -215,6 +215,11 @@
"~0.4.1 | Status": "AssumeBroken",
"~0.4.1 | StatusReasonDetails": "causes freeze during game launch"
},
"UI Info Suite": {
"ID": "Cdaragorn.UiInfoSuite",
"~2.0.0 | Status": "AssumeBroken",
"~2.0.0 | StatusReasonDetails": "causes lag, errors, or crashes in-game"
},
"Video Player": {
"ID": "aedenthorn.VideoPlayer",
"~0.2.5 | Status": "AssumeBroken",

View File

@ -214,7 +214,7 @@
},
"FromFile": {
"title": "Source file",
"description": "The relative file path in your content pack folder to load instead (like 'assets/dinosaur.png'), or multiple comma-delimited values. This can be a .json (data), .png (image), .tbin or .tmx (map), or .xnb file. This field supports tokens and capitalization doesn't matter.",
"description": "The relative file path in your content pack folder to load instead (like 'assets/dinosaur.png'), or multiple comma-delimited values. This can be a .fnt (font), .json (data), .png (image), .tbin or .tmx (map), or .xnb file. This field supports tokens and capitalization doesn't matter.",
"type": "string",
"allOf": [
{
@ -223,12 +223,12 @@
}
},
{
"pattern": "\\.(json|png|tbin|tmx|xnb) *$"
"pattern": "\\.(fnt|json|png|tbin|tmx|xnb) *$"
}
],
"@errorMessages": {
"allOf:indexes: 0": "Invalid value; must not contain directory climbing (like '../').",
"allOf:indexes: 1": "Invalid value; must be a file path ending with .json, .png, .tbin, .tmx, or .xnb."
"allOf:indexes: 1": "Invalid value; must be a file path ending with .fnt, .json, .png, .tbin, .tmx, or .xnb."
}
},
"FromArea": {

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28729.10
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".root", ".root", "{86C452BE-D2D8-45B4-B63F-E329EB06CEDA}"
ProjectSection(SolutionItems) = preProject
@ -28,7 +28,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{09CF91E5
ProjectSection(SolutionItems) = preProject
..\build\common.targets = ..\build\common.targets
..\build\find-game-folder.targets = ..\build\find-game-folder.targets
..\build\prepare-install-package.targets = ..\build\prepare-install-package.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{EB35A917-67B9-4EFA-8DFC-4FB49B3949BB}"
@ -84,6 +83,24 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit.CoreInterface
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windows", "windows", "{4D661178-38FB-43E4-AA5F-9B0406919344}"
ProjectSection(SolutionItems) = preProject
..\build\windows\finalize-install-package.sh = ..\build\windows\finalize-install-package.sh
..\build\windows\prepare-install-package.ps1 = ..\build\windows\prepare-install-package.ps1
..\build\windows\set-smapi-version.ps1 = ..\build\windows\set-smapi-version.ps1
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unix", "unix", "{CAA1488E-842B-433D-994D-1D3D0B5DD125}"
ProjectSection(SolutionItems) = preProject
..\build\unix\prepare-install-package.sh = ..\build\unix\prepare-install-package.sh
..\build\unix\set-smapi-version.sh = ..\build\unix\set-smapi-version.sh
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{3B5BF14D-F612-4C83-9EF6-E3EBFCD08766}"
ProjectSection(SolutionItems) = preProject
..\build\windows\lib\in-place-regex.ps1 = ..\build\windows\lib\in-place-regex.ps1
EndProjectSection
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5
@ -167,6 +184,9 @@ Global
{0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5}
{491E775B-EAD0-44D4-B6CA-F1FC3E316D33} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5}
{CD53AD6F-97F4-4872-A212-50C2A0FD3601} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5}
{4D661178-38FB-43E4-AA5F-9B0406919344} = {09CF91E5-5BAB-4650-A200-E5EA9A633046}
{CAA1488E-842B-433D-994D-1D3D0B5DD125} = {09CF91E5-5BAB-4650-A200-E5EA9A633046}
{3B5BF14D-F612-4C83-9EF6-E3EBFCD08766} = {4D661178-38FB-43E4-AA5F-9B0406919344}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC}

View File

@ -49,7 +49,7 @@ namespace StardewModdingAPI
internal static int? LogScreenId { get; set; }
/// <summary>SMAPI's current raw semantic version.</summary>
internal static string RawApiVersion = "3.13.1";
internal static string RawApiVersion = "3.13.2";
}
/// <summary>Contains SMAPI's constants and assumptions.</summary>

View File

@ -4,6 +4,8 @@ using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using HarmonyLib;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member: This is internal code to support rewriters that shouldn't be called directly.
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
/// <summary>Maps Harmony 1.x <see cref="AccessTools"/> methods to Harmony 2.x to avoid breaking older mods.</summary>

View File

@ -5,6 +5,8 @@ using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member: This is internal code to support rewriters that shouldn't be called directly.
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
/// <summary>Maps Harmony 1.x <code>HarmonyInstance</code> methods to Harmony 2.x's <see cref="Harmony"/> to avoid breaking older mods.</summary>

View File

@ -3,6 +3,8 @@ using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using HarmonyLib;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member: This is internal code to support rewriters that shouldn't be called directly.
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
/// <summary>Maps Harmony 1.x <see cref="HarmonyMethod"/> methods to Harmony 2.x to avoid breaking older mods.</summary>

View File

@ -2,6 +2,9 @@ using System.Diagnostics.CodeAnalysis;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#pragma warning disable CS0109 // Member does not hide an inherited member, new keyword is not required: This is deliberate to support legacy XNA Framework platforms.
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member: This is internal code to support rewriters that shouldn't be called directly.
namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades
{
/// <summary>Provides <see cref="SpriteBatch"/> method signatures that can be injected into mod code for compatibility with mods written for XNA Framework before Stardew Valley 1.5.5.</summary>

View File

@ -776,10 +776,10 @@ namespace StardewModdingAPI.Framework
}
if (!Game1.eventUp && Game1.farmEvent == null && Game1.currentBillboard == 0 && Game1.gameMode == 3 && !this.takingMapScreenshot && Game1.isOutdoorMapSmallerThanViewport())
{
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, -Math.Min(Game1.viewport.X, GameRunner.MaxTextureSize), Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64, 0, Math.Min(GameRunner.MaxTextureSize, Game1.graphics.GraphicsDevice.Viewport.Width - (-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64)), Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, Game1.graphics.GraphicsDevice.Viewport.Width, -Math.Min(Game1.viewport.Y, GameRunner.MaxTextureSize)), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, -Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64, Game1.graphics.GraphicsDevice.Viewport.Width, Math.Min(GameRunner.MaxTextureSize, Game1.graphics.GraphicsDevice.Viewport.Height - (-Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64))), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, -Game1.viewport.X, Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64, 0, Game1.graphics.GraphicsDevice.Viewport.Width - (-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64), Game1.graphics.GraphicsDevice.Viewport.Height), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, 0, Game1.graphics.GraphicsDevice.Viewport.Width, -Game1.viewport.Y), Color.Black);
Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(0, -Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64, Game1.graphics.GraphicsDevice.Viewport.Width, Game1.graphics.GraphicsDevice.Viewport.Height - (-Game1.viewport.Y + Game1.currentLocation.map.Layers[0].LayerHeight * 64)), Color.Black);
}
Game1.spriteBatch.End();
Game1.PushUIMode();

View File

@ -6,7 +6,7 @@ using StardewValley;
namespace StardewModdingAPI
{
/// <summary>A unified button constant which includes all controller, keyboard, and mouse buttons.</summary>
/// <remarks>Derived from <see cref="Keys"/>, <see cref="Buttons"/>, and <see cref="System.Windows.Forms.MouseButtons"/>.</remarks>
/// <remarks>Derived from <see cref="Keys"/>, <see cref="Buttons"/>, and <c>System.Windows.Forms.MouseButtons</c>.</remarks>
public enum SButton
{
/// <summary>No valid key.</summary>

View File

@ -13,6 +13,9 @@
<!--copy dependency DLLs to bin folder so we can include them in installer bundle -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<!-- tiered compilation breaks Harmony -->
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<Import Project="..\..\build\common.targets" />

View File

@ -105,7 +105,9 @@ namespace StardewModdingAPI.Utilities
/// <summary>Get the keybind state relative to the previous tick.</summary>
public SButtonState GetState()
{
#pragma warning disable CS0618 // Type or member is obsolete: deliberate call to GetButtonState() for unit tests
SButtonState[] states = this.Buttons.Select(this.GetButtonState).Distinct().ToArray();
#pragma warning restore CS0618
// single state
if (states.Length == 1)

View File

@ -1,6 +1,6 @@
{
// short date format for SDate
// tokens: {{day}} (like 15), {{season}} (like Spring), {{seasonLowercase}} (like spring), {{year}} (like 2)
"generic.date": "{{day}} {{seasonLowercase}}",
"generic.date-with-year": "{{day}} {{seasonLowercase}} w roku {{year}}"
}
{
// short date format for SDate
// tokens: {{day}} (like 15), {{season}} (like Spring), {{seasonLowercase}} (like spring), {{year}} (like 2)
"generic.date": "{{day}} {{seasonLowercase}}",
"generic.date-with-year": "{{day}} {{seasonLowercase}} w roku {{year}}"
}