Compare commits
9 Commits
develop
...
archived/c
Author | SHA1 | Date |
---|---|---|
ClxS | 65f1e5bec4 | |
ClxS | 1ec0570ed9 | |
ClxS | e1bfd54894 | |
ClxS | 792cfcd796 | |
ClxS | 608a5cb257 | |
ClxS | 8201b96034 | |
ClxS | c8e09331d2 | |
ClxS | 27bc612a46 | |
ClxS | 318f5feada |
|
@ -1,81 +0,0 @@
|
||||||
# topmost editorconfig
|
|
||||||
root: true
|
|
||||||
|
|
||||||
##########
|
|
||||||
## General formatting
|
|
||||||
## documentation: https://editorconfig.org
|
|
||||||
##########
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
charset = utf-8
|
|
||||||
|
|
||||||
[*.{csproj,nuspec,targets}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.csproj]
|
|
||||||
charset = utf-8-bom
|
|
||||||
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
|
|
||||||
##########
|
|
||||||
[*.cs]
|
|
||||||
|
|
||||||
#sort 'system' usings first
|
|
||||||
dotnet_sort_system_directives_first = true
|
|
||||||
|
|
||||||
# use 'this.' qualifier
|
|
||||||
dotnet_style_qualification_for_field = true:error
|
|
||||||
dotnet_style_qualification_for_property = true:error
|
|
||||||
dotnet_style_qualification_for_method = true:error
|
|
||||||
dotnet_style_qualification_for_event = true:error
|
|
||||||
|
|
||||||
# use language keywords (like int) instead of type (like Int32)
|
|
||||||
dotnet_style_predefined_type_for_locals_parameters_members = true:error
|
|
||||||
dotnet_style_predefined_type_for_member_access = true:error
|
|
||||||
|
|
||||||
# don't use 'var' for language keywords
|
|
||||||
csharp_style_var_for_built_in_types = false:error
|
|
||||||
|
|
||||||
# suggest modern C# features where simpler
|
|
||||||
dotnet_style_object_initializer = true:suggestion
|
|
||||||
dotnet_style_collection_initializer = true:suggestion
|
|
||||||
dotnet_style_coalesce_expression = true:suggestion
|
|
||||||
dotnet_style_null_propagation = true:suggestion
|
|
||||||
dotnet_style_explicit_tuple_names = true:suggestion
|
|
||||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
|
||||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
|
||||||
csharp_style_conditional_delegate_call = true:suggestion
|
|
||||||
csharp_prefer_simple_default_expression = true:suggestion
|
|
||||||
|
|
||||||
# prefer method block bodies
|
|
||||||
csharp_style_expression_bodied_methods = false:suggestion
|
|
||||||
csharp_style_expression_bodied_constructors = false:suggestion
|
|
||||||
|
|
||||||
# prefer property expression bodies
|
|
||||||
csharp_style_expression_bodied_properties = true:suggestion
|
|
||||||
csharp_style_expression_bodied_indexers = true:suggestion
|
|
||||||
csharp_style_expression_bodied_accessors = true:suggestion
|
|
||||||
|
|
||||||
# prefer inline out variables
|
|
||||||
csharp_style_inlined_variable_declaration = true:warning
|
|
||||||
|
|
||||||
# avoid superfluous braces
|
|
||||||
csharp_prefer_braces = false:hint
|
|
||||||
|
|
||||||
##########
|
|
||||||
## Column guidelines
|
|
||||||
## documentation: https://marketplace.visualstudio.com/items?itemName=PaulHarrington.EditorGuidelines
|
|
||||||
##########
|
|
||||||
[*.md]
|
|
||||||
guidelines = 100
|
|
|
@ -1,6 +0,0 @@
|
||||||
# normalize line endings
|
|
||||||
* text=auto
|
|
||||||
README.txt text eol=crlf
|
|
||||||
|
|
||||||
*.command text eol=lf
|
|
||||||
*.sh text eol=lf
|
|
|
@ -1,12 +0,0 @@
|
||||||
Do you want to...
|
|
||||||
|
|
||||||
* **Ask for help or report a bug?**
|
|
||||||
Please see 'get help' on [the SMAPI website](https://smapi.io) instead, don't create a GitHub
|
|
||||||
issue.
|
|
||||||
|
|
||||||
* **Submit a pull request?**
|
|
||||||
Pull requests are welcome! If you're submitting a new feature, it's best to discuss first to make
|
|
||||||
sure it'll be accepted. Feel free to come chat [on Discord](https://smapi.io/community).
|
|
||||||
|
|
||||||
Documenting your code and using the same formatting conventions is appreciated, but don't worry too
|
|
||||||
much about it. We'll fix up the code after we accept the pull request if needed.
|
|
|
@ -1,3 +0,0 @@
|
||||||
patreon: pathoschild
|
|
||||||
ko_fi: pathoschild
|
|
||||||
custom: https://www.paypal.me/pathoschild
|
|
|
@ -1,8 +0,0 @@
|
||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: Troubleshooting guide for players
|
|
||||||
url: https://smapi.io/troubleshoot
|
|
||||||
about: See if your question is already answered first!
|
|
||||||
- name: Get help or discuss
|
|
||||||
url: https://smapi.io/help
|
|
||||||
about: Ask for help from the community, or join the Stardew Valley Discord to ask questions, report issues, or discuss with the SMAPI developer, players, and mod authors. The SMAPI developer is @Pathoschild#0001 on Discord.
|
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
name: Create a development task
|
|
||||||
about: DON'T DO THIS BEFORE READING. This is for specific changes to the code or technical bug reports. See below if something isn't working, you have questions or ideas, or you want to discuss something.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
STOP!
|
|
||||||
|
|
||||||
Is this a specific development task? Don't create an issue if not!
|
|
||||||
See https://smapi.io/community if something isn't working, you have questions or ideas, or you want
|
|
||||||
to discuss something.
|
|
||||||
|
|
||||||
If you're absolutely sure it's a specific development task (e.g. a specific bug, not just
|
|
||||||
'something went wrong on my computer'), edit the template below.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is. Provide any other details you think might be relevant here.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Exact steps which reproduce the bug, if possible. For example:
|
|
||||||
1. Load save '...'.
|
|
||||||
2. Walk to '....'.
|
|
||||||
3. Click '....'.
|
|
||||||
4. Error occurs.
|
|
||||||
|
|
||||||
**Log file**
|
|
||||||
Upload your SMAPI log to https://smapi.io/log and post a link here.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
|
@ -1,3 +0,0 @@
|
||||||
GitHub issues are only used for SMAPI development tasks.
|
|
||||||
|
|
||||||
To get help with SMAPI problems, see 'get help' on [the SMAPI website](https://smapi.io/) instead.
|
|
|
@ -1,47 +1,261 @@
|
||||||
# user-specific files
|
# SMAPI Specific Ignores
|
||||||
|
StardewModdingAPI/bin/
|
||||||
|
StardewModdingAPI/obj/
|
||||||
|
TrainerMod/bin/
|
||||||
|
TrainerMod/obj/
|
||||||
|
StardewInjector/bin/
|
||||||
|
StardewInjector/obj/
|
||||||
|
packages/
|
||||||
|
|
||||||
|
*.symlink
|
||||||
|
*.lnk
|
||||||
|
!*.exe
|
||||||
|
!*.dll
|
||||||
|
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
|
||||||
# build results
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
[Rr]elease/
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
# Visual Studio cache/options
|
# Visual Studio 2015 cache/options directory
|
||||||
.config/
|
|
||||||
.vs/
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
# ReSharper
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# DNX
|
||||||
|
project.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
_ReSharper*/
|
_ReSharper*/
|
||||||
*.[Rr]e[Ss]harper
|
*.[Rr]e[Ss]harper
|
||||||
*.DotSettings.user
|
*.DotSettings.user
|
||||||
|
|
||||||
# Rider
|
# JustCode is a .NET coding add-in
|
||||||
.idea/
|
.JustCode
|
||||||
|
|
||||||
# NuGet packages
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
**/packages/*
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignoreable files
|
||||||
*.nuget.props
|
*.nuget.props
|
||||||
*.nuget.targets
|
*.nuget.targets
|
||||||
|
|
||||||
# sensitive files
|
# Microsoft Azure Build Output
|
||||||
appsettings.Development.json
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
# Azure generated files
|
# Microsoft Azure Emulator
|
||||||
src/SMAPI.Web/Properties/PublishProfiles/*.pubxml
|
ecf/
|
||||||
src/SMAPI.Web/Properties/ServiceDependencies/* - Web Deploy/
|
rcf/
|
||||||
|
|
||||||
# macOS
|
# Microsoft Azure ApplicationInsights config file
|
||||||
.DS_Store
|
ApplicationInsights.config
|
||||||
|
|
||||||
# Loader Game Asserts
|
# Windows Store app package directories and files
|
||||||
src/Loader/Assets/Content/
|
AppPackages/
|
||||||
src/Loader/libs/
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
|
||||||
# VSHistory
|
# Visual Studio cache files
|
||||||
**/.vshistory/
|
# files ending in .cache can be ignored
|
||||||
/build/StardewValleyAndroidStuff/
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
|
@ -0,0 +1,40 @@
|
||||||
|
Single difficulty
|
||||||
|
Int32 motionType
|
||||||
|
Int32 whichFish
|
||||||
|
Single bobberPosition
|
||||||
|
Single bobberSpeed
|
||||||
|
Single bobberAcceleration
|
||||||
|
Single bobberTargetPosition
|
||||||
|
Single scale
|
||||||
|
Single everythingShakeTimer
|
||||||
|
Single floaterSinkerAcceleration
|
||||||
|
Single treasurePosition
|
||||||
|
Single treasureCatchLevel
|
||||||
|
Single treasureAppearTimer
|
||||||
|
Single treasureScale
|
||||||
|
Boolean bobberInBar
|
||||||
|
Boolean buttonPressed
|
||||||
|
Boolean flipBubble
|
||||||
|
Boolean fadeIn
|
||||||
|
Boolean fadeOut
|
||||||
|
Boolean treasure
|
||||||
|
Boolean treasureCaught
|
||||||
|
Boolean perfect
|
||||||
|
Boolean bossFish
|
||||||
|
Int32 bobberBarHeight
|
||||||
|
Int32 fishSize
|
||||||
|
Int32 fishQuality
|
||||||
|
Int32 minFishSize
|
||||||
|
Int32 maxFishSize
|
||||||
|
Int32 fishSizeReductionTimer
|
||||||
|
Int32 whichBobber
|
||||||
|
Microsoft.Xna.Framework.Vector2 barShake
|
||||||
|
Microsoft.Xna.Framework.Vector2 fishShake
|
||||||
|
Microsoft.Xna.Framework.Vector2 everythingShake
|
||||||
|
Microsoft.Xna.Framework.Vector2 treasureShake
|
||||||
|
Single reelRotation
|
||||||
|
StardewValley.BellsAndWhistles.SparklingText sparkleText
|
||||||
|
Single bobberBarPos
|
||||||
|
Single bobberBarSpeed
|
||||||
|
Single bobberBarAcceleration
|
||||||
|
Single distanceFromCatching
|
|
@ -0,0 +1,329 @@
|
||||||
|
Int32 pixelZoom
|
||||||
|
Int32 tileSize
|
||||||
|
System.String version
|
||||||
|
Microsoft.Xna.Framework.GraphicsDeviceManager graphics
|
||||||
|
Microsoft.Xna.Framework.Content.ContentManager content
|
||||||
|
Microsoft.Xna.Framework.Content.ContentManager temporaryContent
|
||||||
|
Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch
|
||||||
|
Microsoft.Xna.Framework.Input.GamePadState oldPadState
|
||||||
|
Single thumbStickSensitivity
|
||||||
|
Single runThreshold
|
||||||
|
Microsoft.Xna.Framework.Input.KeyboardState oldKBState
|
||||||
|
Microsoft.Xna.Framework.Input.MouseState oldMouseState
|
||||||
|
System.Collections.Generic.List`1[StardewValley.GameLocation] locations
|
||||||
|
StardewValley.GameLocation currentLocation
|
||||||
|
StardewValley.GameLocation locationAfterWarp
|
||||||
|
xTile.Display.IDisplayDevice mapDisplayDevice
|
||||||
|
StardewValley.Farmer player
|
||||||
|
StardewValley.Farmer serverHost
|
||||||
|
xTile.Dimensions.Rectangle viewport
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D objectSpriteSheet
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D toolSpriteSheet
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D cropSpriteSheet
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D mailboxTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D emoteSpriteSheet
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D debrisSpriteSheet
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D toolIconBox
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D rainTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D bigCraftableSpriteSheet
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D swordSwipe
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D swordSwipeDark
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D buffsIcons
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D daybg
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D nightbg
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D logoScreenTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D tvStationTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D cloud
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D menuTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D lantern
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D windowLight
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D sconceLight
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D cauldronLight
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D shadowTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D mouseCursors
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D indoorWindowLight
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D animations
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D titleScreenBG
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D logo
|
||||||
|
Microsoft.Xna.Framework.Graphics.RenderTarget2D lightmap
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D fadeToBlackRect
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D staminaRect
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D currentCoopTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D currentBarnTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D currentHouseTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D greenhouseTexture
|
||||||
|
Microsoft.Xna.Framework.Graphics.Texture2D littleEffect
|
||||||
|
Microsoft.Xna.Framework.Graphics.SpriteFont dialogueFont
|
||||||
|
Microsoft.Xna.Framework.Graphics.SpriteFont smallFont
|
||||||
|
Microsoft.Xna.Framework.Graphics.SpriteFont borderFont
|
||||||
|
Microsoft.Xna.Framework.Graphics.SpriteFont tinyFont
|
||||||
|
Microsoft.Xna.Framework.Graphics.SpriteFont tinyFontBorder
|
||||||
|
Microsoft.Xna.Framework.Graphics.SpriteFont smoothFont
|
||||||
|
Single fadeToBlackAlpha
|
||||||
|
Single pickToolInterval
|
||||||
|
Single screenGlowAlpha
|
||||||
|
Single flashAlpha
|
||||||
|
Single starCropShimmerPause
|
||||||
|
Single noteBlockTimer
|
||||||
|
Single globalFadeSpeed
|
||||||
|
Boolean fadeToBlack
|
||||||
|
Boolean fadeIn
|
||||||
|
Boolean dialogueUp
|
||||||
|
Boolean dialogueTyping
|
||||||
|
Boolean pickingTool
|
||||||
|
Boolean isQuestion
|
||||||
|
Boolean nonWarpFade
|
||||||
|
Boolean particleRaining
|
||||||
|
Boolean newDay
|
||||||
|
Boolean inMine
|
||||||
|
Boolean isEating
|
||||||
|
Boolean menuUp
|
||||||
|
Boolean eventUp
|
||||||
|
Boolean viewportFreeze
|
||||||
|
Boolean eventOver
|
||||||
|
Boolean nameSelectUp
|
||||||
|
Boolean screenGlow
|
||||||
|
Boolean screenGlowHold
|
||||||
|
Boolean screenGlowUp
|
||||||
|
Boolean progressBar
|
||||||
|
Boolean isRaining
|
||||||
|
Boolean isSnowing
|
||||||
|
Boolean killScreen
|
||||||
|
Boolean coopDwellerBorn
|
||||||
|
Boolean messagePause
|
||||||
|
Boolean isDebrisWeather
|
||||||
|
Boolean boardingBus
|
||||||
|
Boolean listeningForKeyControlDefinitions
|
||||||
|
Boolean weddingToday
|
||||||
|
Boolean exitToTitle
|
||||||
|
Boolean debugMode
|
||||||
|
Boolean isLightning
|
||||||
|
Boolean displayHUD
|
||||||
|
Boolean displayFarmer
|
||||||
|
Boolean showKeyHelp
|
||||||
|
Boolean inputMode
|
||||||
|
Boolean shippingTax
|
||||||
|
Boolean dialogueButtonShrinking
|
||||||
|
Boolean jukeboxPlaying
|
||||||
|
Boolean drawLighting
|
||||||
|
Boolean bloomDay
|
||||||
|
Boolean quit
|
||||||
|
Boolean isChatting
|
||||||
|
Boolean globalFade
|
||||||
|
Boolean drawGrid
|
||||||
|
Boolean freezeControls
|
||||||
|
Boolean saveOnNewDay
|
||||||
|
Boolean panMode
|
||||||
|
Boolean showingEndOfNightStuff
|
||||||
|
Boolean wasRainingYesterday
|
||||||
|
Boolean hasLoadedGame
|
||||||
|
Boolean isActionAtCurrentCursorTile
|
||||||
|
Boolean isInspectionAtCurrentCursorTile
|
||||||
|
Boolean paused
|
||||||
|
Boolean lastCursorMotionWasMouse
|
||||||
|
System.String currentSeason
|
||||||
|
System.String debugOutput
|
||||||
|
System.String nextMusicTrack
|
||||||
|
System.String selectedItemsType
|
||||||
|
System.String nameSelectType
|
||||||
|
System.String messageAfterPause
|
||||||
|
System.String fertilizer
|
||||||
|
System.String samBandName
|
||||||
|
System.String elliottBookName
|
||||||
|
System.String slotResult
|
||||||
|
System.String keyHelpString
|
||||||
|
System.String debugInput
|
||||||
|
System.String loadingMessage
|
||||||
|
System.String errorMessage
|
||||||
|
System.Collections.Generic.Queue`1[System.String] currentObjectDialogue
|
||||||
|
System.Collections.Generic.Queue`1[System.String] mailbox
|
||||||
|
System.Collections.Generic.List`1[System.String] questionChoices
|
||||||
|
Int32 xLocationAfterWarp
|
||||||
|
Int32 yLocationAfterWarp
|
||||||
|
Int32 gameTimeInterval
|
||||||
|
Int32 currentQuestionChoice
|
||||||
|
Int32 currentDialogueCharacterIndex
|
||||||
|
Int32 dialogueTypingInterval
|
||||||
|
Int32 dayOfMonth
|
||||||
|
Int32 year
|
||||||
|
Int32 timeOfDay
|
||||||
|
Int32 numberOfSelectedItems
|
||||||
|
Int32 priceOfSelectedItem
|
||||||
|
Int32 currentWallpaper
|
||||||
|
Int32 farmerWallpaper
|
||||||
|
Int32 wallpaperPrice
|
||||||
|
Int32 currentFloor
|
||||||
|
Int32 FarmerFloor
|
||||||
|
Int32 floorPrice
|
||||||
|
Int32 dialogueWidth
|
||||||
|
Int32 countdownToWedding
|
||||||
|
Int32 menuChoice
|
||||||
|
Int32 tvStation
|
||||||
|
Int32 currentBillboard
|
||||||
|
Int32 facingDirectionAfterWarp
|
||||||
|
Int32 tmpTimeOfDay
|
||||||
|
Int32 percentageToWinStardewHero
|
||||||
|
Int32 mouseClickPolling
|
||||||
|
Int32 weatherIcon
|
||||||
|
Int32 hitShakeTimer
|
||||||
|
Int32 staminaShakeTimer
|
||||||
|
Int32 pauseThenDoFunctionTimer
|
||||||
|
Int32 weatherForTomorrow
|
||||||
|
Int32 currentSongIndex
|
||||||
|
Int32 cursorTileHintCheckTimer
|
||||||
|
Int32 timerUntilMouseFade
|
||||||
|
Int32 minecartHighScore
|
||||||
|
System.Collections.Generic.List`1[System.Int32] dealerCalicoJackTotal
|
||||||
|
Microsoft.Xna.Framework.Color morningColor
|
||||||
|
Microsoft.Xna.Framework.Color eveningColor
|
||||||
|
Microsoft.Xna.Framework.Color unselectedOptionColor
|
||||||
|
Microsoft.Xna.Framework.Color screenGlowColor
|
||||||
|
StardewValley.NPC currentSpeaker
|
||||||
|
System.Random random
|
||||||
|
System.Random recentMultiplayerRandom
|
||||||
|
System.Collections.Generic.Dictionary`2[System.Int32,System.String] objectInformation
|
||||||
|
System.Collections.Generic.Dictionary`2[System.Int32,System.String] bigCraftablesInformation
|
||||||
|
System.Collections.Generic.List`1[StardewValley.Object] shippingBin
|
||||||
|
StardewValley.Locations.MineShaft mine
|
||||||
|
System.Collections.Generic.List`1[StardewValley.HUDMessage] hudMessages
|
||||||
|
System.Collections.Generic.Dictionary`2[System.String,System.Boolean] eventConditions
|
||||||
|
System.Collections.Generic.Dictionary`2[System.String,System.String] NPCGiftTastes
|
||||||
|
Single musicPlayerVolume
|
||||||
|
Single pauseAccumulator
|
||||||
|
Single pauseTime
|
||||||
|
Single upPolling
|
||||||
|
Single downPolling
|
||||||
|
Single rightPolling
|
||||||
|
Single leftPolling
|
||||||
|
Single debrisSoundInterval
|
||||||
|
Single toolHold
|
||||||
|
Single windGust
|
||||||
|
Single dialogueButtonScale
|
||||||
|
Single creditsTimer
|
||||||
|
Single globalOutdoorLighting
|
||||||
|
Microsoft.Xna.Framework.Audio.Cue currentSong
|
||||||
|
Microsoft.Xna.Framework.Audio.AudioCategory musicCategory
|
||||||
|
Microsoft.Xna.Framework.Audio.AudioCategory soundCategory
|
||||||
|
Microsoft.Xna.Framework.PlayerIndex playerOneIndex
|
||||||
|
Microsoft.Xna.Framework.Audio.AudioEngine audioEngine
|
||||||
|
Microsoft.Xna.Framework.Audio.WaveBank waveBank
|
||||||
|
Microsoft.Xna.Framework.Audio.SoundBank soundBank
|
||||||
|
Microsoft.Xna.Framework.Vector2 shiny
|
||||||
|
Microsoft.Xna.Framework.Vector2 previousViewportPosition
|
||||||
|
Microsoft.Xna.Framework.Vector2 currentCursorTile
|
||||||
|
Microsoft.Xna.Framework.Vector2 lastCursorTile
|
||||||
|
StardewValley.RainDrop[] rainDrops
|
||||||
|
Double chanceToRainTomorrow
|
||||||
|
Microsoft.Xna.Framework.Audio.Cue fuseSound
|
||||||
|
Microsoft.Xna.Framework.Audio.Cue chargeUpSound
|
||||||
|
Microsoft.Xna.Framework.Audio.Cue wind
|
||||||
|
Double dailyLuck
|
||||||
|
System.Collections.Generic.List`1[StardewValley.WeatherDebris] debrisWeather
|
||||||
|
System.Collections.Generic.List`1[StardewValley.TemporaryAnimatedSprite] screenOverlayTempSprites
|
||||||
|
Byte gameMode
|
||||||
|
Byte multiplayerMode
|
||||||
|
System.Collections.Generic.IEnumerator`1[System.Int32] currentLoader
|
||||||
|
UInt64 uniqueIDForThisGame
|
||||||
|
StardewValley.LoadGameScreen loadGameScreen
|
||||||
|
StardewValley.Stats stats
|
||||||
|
Int32[] cropsOfTheWeek
|
||||||
|
StardewValley.Quests.Quest questOfTheDay
|
||||||
|
StardewValley.MoneyMadeScreen moneyMadeScreen
|
||||||
|
System.Collections.Generic.HashSet`1[StardewValley.LightSource] currentLightSources
|
||||||
|
Microsoft.Xna.Framework.Color ambientLight
|
||||||
|
Microsoft.Xna.Framework.Color outdoorLight
|
||||||
|
Microsoft.Xna.Framework.Color textColor
|
||||||
|
Microsoft.Xna.Framework.Color textShadowColor
|
||||||
|
StardewValley.Menus.IClickableMenu activeClickableMenu
|
||||||
|
StardewValley.Minigames.IMinigame currentMinigame
|
||||||
|
System.Collections.Generic.List`1[StardewValley.Menus.IClickableMenu] onScreenMenus
|
||||||
|
StardewValley.BloomComponent bloom
|
||||||
|
System.Collections.Generic.Dictionary`2[System.Int32,System.String] achievements
|
||||||
|
StardewValley.Object dishOfTheDay
|
||||||
|
StardewValley.Menus.BuffsDisplay buffsDisplay
|
||||||
|
StardewValley.Menus.DayTimeMoneyBox dayTimeMoneyBox
|
||||||
|
System.Collections.Generic.Dictionary`2[System.Int64,StardewValley.Farmer] otherFarmers
|
||||||
|
StardewValley.Network.Server server
|
||||||
|
StardewValley.Network.Client client
|
||||||
|
StardewValley.KeyboardDispatcher keyboardDispatcher
|
||||||
|
StardewValley.Background background
|
||||||
|
StardewValley.Events.FarmEvent farmEvent
|
||||||
|
afterFadeFunction afterFade
|
||||||
|
afterFadeFunction afterDialogues
|
||||||
|
afterFadeFunction afterViewport
|
||||||
|
afterFadeFunction viewportReachedTarget
|
||||||
|
afterFadeFunction afterPause
|
||||||
|
Microsoft.Xna.Framework.GameTime currentGameTime
|
||||||
|
System.Collections.Generic.List`1[StardewValley.DelayedAction] delayedActions
|
||||||
|
System.Collections.Generic.Stack`1[StardewValley.Menus.IClickableMenu] endOfNightMenus
|
||||||
|
StardewValley.Options options
|
||||||
|
StardewValley.Game1 game1
|
||||||
|
Microsoft.Xna.Framework.Point lastMousePositionBeforeFade
|
||||||
|
Microsoft.Xna.Framework.Point viewportCenter
|
||||||
|
Microsoft.Xna.Framework.Vector2 viewportTarget
|
||||||
|
Single viewportSpeed
|
||||||
|
Int32 viewportHold
|
||||||
|
Boolean toggleFullScreen
|
||||||
|
Boolean isFullscreen
|
||||||
|
Boolean setToWindowedMode
|
||||||
|
Boolean setToFullscreen
|
||||||
|
System.String whereIsTodaysFest
|
||||||
|
Boolean farmerShouldPassOut
|
||||||
|
Microsoft.Xna.Framework.Vector2 currentViewportTarget
|
||||||
|
Microsoft.Xna.Framework.Vector2 viewportPositionLerp
|
||||||
|
Single screenGlowRate
|
||||||
|
Single screenGlowMax
|
||||||
|
Boolean haltAfterCheck
|
||||||
|
Int32 mouseCursor
|
||||||
|
Single mouseCursorTransparency
|
||||||
|
StardewValley.NPC objectDialoguePortraitPerson
|
||||||
|
Int32 defaultResolutionX
|
||||||
|
Int32 defaultResolutionY
|
||||||
|
Int32 smallestTileSize
|
||||||
|
Int32 up
|
||||||
|
Int32 right
|
||||||
|
Int32 down
|
||||||
|
Int32 left
|
||||||
|
Int32 spriteIndexForOveralls
|
||||||
|
Int32 colorToleranceForOveralls
|
||||||
|
Int32 spriteIndexForOverallsBorder
|
||||||
|
Int32 colorToloranceForOverallsBorder
|
||||||
|
Int32 dialogueBoxTileHeight
|
||||||
|
Int32 realMilliSecondsPerGameTenMinutes
|
||||||
|
Int32 rainDensity
|
||||||
|
Int32 millisecondsPerDialogueLetterType
|
||||||
|
Single pickToolDelay
|
||||||
|
Int32 defaultMinFishingBiteTime
|
||||||
|
Int32 defaultMaxFishingBiteTime
|
||||||
|
Int32 defaultMinFishingNibbleTime
|
||||||
|
Int32 defaultMaxFishingNibbleTime
|
||||||
|
Int32 minWallpaperPrice
|
||||||
|
Int32 maxWallpaperPrice
|
||||||
|
Int32 rainLoopLength
|
||||||
|
Int32 weather_sunny
|
||||||
|
Int32 weather_rain
|
||||||
|
Int32 weather_debris
|
||||||
|
Int32 weather_lightning
|
||||||
|
Int32 weather_festival
|
||||||
|
Int32 weather_snow
|
||||||
|
Int32 weather_wedding
|
||||||
|
Byte singlePlayer
|
||||||
|
Byte multiplayerClient
|
||||||
|
Byte multiplayerServer
|
||||||
|
Byte logoScreenGameMode
|
||||||
|
Byte titleScreenGameMode
|
||||||
|
Byte loadScreenGameMode
|
||||||
|
Byte newGameMode
|
||||||
|
Byte playingGameMode
|
||||||
|
Byte characterSelectMode
|
||||||
|
Byte loadingMode
|
||||||
|
Byte saveMode
|
||||||
|
Byte saveCompleteMode
|
||||||
|
Byte selectGameScreen
|
||||||
|
Byte creditsMode
|
||||||
|
Byte errorLogMode
|
||||||
|
Single keyPollingThreshold
|
||||||
|
Single toolHoldPerPowerupLevel
|
||||||
|
Single startingMusicVolume
|
||||||
|
Single thumbstickToMouseModifier
|
||||||
|
System.String NO_LETTER_MAIL
|
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
{one line to give the program's name and a brief idea of what it does.}
|
||||||
|
Copyright (C) {year} {name of author}
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
{project} Copyright (C) {year} {fullname}
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
165
LICENSE.txt
|
@ -1,165 +0,0 @@
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
## NOTICE: THIS PROJECT IS STILL IN ALPHA
|
||||||
|
|
||||||
|
# What is SMAPI
|
||||||
|
|
||||||
|
SMAPI (Stardew Mapping Application Programming Interface) is a tool to help modders make changes to Stardew. It is a standalone executable which goes alongside your Stardew.exe.
|
||||||
|
|
||||||
|
## Latest Version: 0.37.2
|
||||||
|
- Added KeyReleased event
|
||||||
|
- Added event handlers for GamePads
|
||||||
|
- Internal Cleanup
|
||||||
|
Tested and works with current versions of: SmartMod, StardewCJB , FreezeInside
|
||||||
|
|
||||||
|
Download: https://github.com/ClxS/SMAPI/releases/tag/0.37.2
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To install SMAPI:
|
||||||
|
- Firstly, make sure you have .NET 4.5. You can get it here: https://www.microsoft.com/en-gb/download/details.aspx?id=30653
|
||||||
|
- Download the the latest release binary here: https://github.com/ClxS/SMAPI/releases/latest
|
||||||
|
- Extract the zip file alongside your Stardew.exe, for example, if using Steam this would be somewhere like C:/ProgramFiles/Steam/steamapps/common/StardewValley
|
||||||
|
- To launch SMAPI, launch StardewValleyModdingAPI.exe
|
||||||
|
|
||||||
|
To install mods:
|
||||||
|
- To install mods just download the mod's .DLL file, and place it in %appdata%\StardewValley\Mods\. SMAPI will take care of the rest!
|
||||||
|
|
||||||
|
## Future Plans
|
||||||
|
- Content only mods
|
||||||
|
- Support for a wide range of events
|
||||||
|
- Enable the addition of new custom content such as locations, NPCs, and items.
|
||||||
|
|
||||||
|
## Mod Developers!
|
||||||
|
|
||||||
|
Mod developers would work off the release branch. The master branch will contain mid-version updates which could make your mods incompatable with both the current release and the upcoming releases.
|
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 14
|
||||||
|
VisualStudioVersion = 14.0.24720.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrainerMod", "TrainerMod\TrainerMod.csproj", "{28480467-1A48-46A7-99F8-236D95225359}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI", "StardewModdingAPI\StardewModdingAPI.csproj", "{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|Mixed Platforms = Release|Mixed Platforms
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{28480467-1A48-46A7-99F8-236D95225359}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|Mixed Platforms.Build.0 = Release|x86
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.API
|
||||||
|
{
|
||||||
|
class Game
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
|
||||||
|
</startup>
|
||||||
|
<runtime>
|
||||||
|
<loadFromRemoteSources enabled="true"/>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,108 @@
|
||||||
|
using StardewModdingAPI.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
public class Command
|
||||||
|
{
|
||||||
|
internal static List<Command> RegisteredCommands = new List<Command>();
|
||||||
|
|
||||||
|
public String CommandName;
|
||||||
|
public String CommandDesc;
|
||||||
|
public String[] CommandArgs;
|
||||||
|
public String[] CalledArgs;
|
||||||
|
public event EventHandler<EventArgsCommand> CommandFired;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calls the specified command. (It runs the command)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The command to run</param>
|
||||||
|
public static void CallCommand(string input)
|
||||||
|
{
|
||||||
|
input = input.TrimEnd(new[] {' '});
|
||||||
|
string[] args = new string[0];
|
||||||
|
Command fnd;
|
||||||
|
if (input.Contains(" "))
|
||||||
|
{
|
||||||
|
args = input.Split(new[] {" "}, 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
fnd = FindCommand(args[0]);
|
||||||
|
args = args[1].Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fnd = FindCommand(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fnd != null)
|
||||||
|
{
|
||||||
|
fnd.CalledArgs = args;
|
||||||
|
fnd.Fire();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("Unknown Command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a command to the list of commands properly
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">Name of the command to register</param>
|
||||||
|
/// <param name="cdesc">Description</param>
|
||||||
|
/// <param name="args">Arguments (these are purely for viewing so that a user can see what an argument needs to be)</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Command RegisterCommand(string command, string cdesc, string[] args = null)
|
||||||
|
{
|
||||||
|
Command c = new Command(command, cdesc, args);
|
||||||
|
if (RegisteredCommands.Contains(c))
|
||||||
|
{
|
||||||
|
Log.Error("Command already registered! [{0}]", c.CommandName);
|
||||||
|
return RegisteredCommands.Find(x => x.Equals(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisteredCommands.Add(c);
|
||||||
|
Log.Verbose("Registered command: " + command);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a command in the list of registered commands. Returns null if it doesn't exist (I think)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Name of command to find</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Command FindCommand(string name)
|
||||||
|
{
|
||||||
|
return RegisteredCommands.Find(x => x.CommandName.Equals(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a Command from a Name, Description, and Arguments
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cname">Name</param>
|
||||||
|
/// <param name="cdesc">Description</param>
|
||||||
|
/// <param name="args">Arguments</param>
|
||||||
|
public Command(String cname, String cdesc, String[] args = null)
|
||||||
|
{
|
||||||
|
CommandName = cname;
|
||||||
|
CommandDesc = cdesc;
|
||||||
|
if (args == null)
|
||||||
|
args = new string[0];
|
||||||
|
CommandArgs = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs a command. Fires it. Calls it. Any of those.
|
||||||
|
/// </summary>
|
||||||
|
public void Fire()
|
||||||
|
{
|
||||||
|
if (CommandFired == null)
|
||||||
|
{
|
||||||
|
Log.Error("Command failed to fire because it's fire event is null: " + CommandName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CommandFired.Invoke(this, new EventArgsCommand(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Static class containing readonly values.
|
||||||
|
/// </summary>
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stardew Valley's local app data location.
|
||||||
|
/// %LocalAppData%//StardewValley
|
||||||
|
/// </summary>
|
||||||
|
public static string DataPath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execution path to execute the code.
|
||||||
|
/// </summary>
|
||||||
|
public static string ExecutionPath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execution path to execute the code.
|
||||||
|
/// </summary>
|
||||||
|
public static string StardewExePath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\Stardew Valley.exe";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Title for the API console
|
||||||
|
/// </summary>
|
||||||
|
public static string ConsoleTitle => string.Format("Stardew Modding API Console - Version {0}", VersionString);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path for log files to be output to.
|
||||||
|
/// %LocalAppData%//StardewValley//ErrorLogs
|
||||||
|
/// </summary>
|
||||||
|
public static string LogPath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "ErrorLogs");
|
||||||
|
|
||||||
|
public const int MajorVersion = 0;
|
||||||
|
|
||||||
|
public const int MinorVersion = 37;
|
||||||
|
|
||||||
|
public const int PatchVersion = 2;
|
||||||
|
|
||||||
|
public const string Build = "Alpha";
|
||||||
|
|
||||||
|
public static string VersionString => string.Format("{0}.{1}.{2} {3}", MajorVersion, MinorVersion, PatchVersion, Build);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Entities
|
||||||
|
{
|
||||||
|
class SCharacter
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Entities
|
||||||
|
{
|
||||||
|
class SFarm
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Entities
|
||||||
|
{
|
||||||
|
class SFarmAnimal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Entities
|
||||||
|
{
|
||||||
|
class SNpc
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using StardewModdingAPI.Inheritance;
|
||||||
|
using StardewValley;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Entities
|
||||||
|
{
|
||||||
|
public static class SPlayer
|
||||||
|
{
|
||||||
|
public static List<Farmer> AllFarmers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return SGame.getAllFarmers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Farmer CurrentFarmer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return SGame.player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameLocation CurrentFarmerLocation
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return SGame.player.currentLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class ControlEvents
|
||||||
|
{
|
||||||
|
public static event EventHandler<EventArgsKeyboardStateChanged> KeyboardChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsKeyPressed> KeyPressed = delegate { };
|
||||||
|
public static event EventHandler<EventArgsKeyPressed> KeyReleased = delegate { };
|
||||||
|
public static event EventHandler<EventArgsMouseStateChanged> MouseChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsControllerButtonPressed> ControllerButtonPressed = delegate { };
|
||||||
|
public static event EventHandler<EventArgsControllerButtonReleased> ControllerButtonReleased = delegate { };
|
||||||
|
public static event EventHandler<EventArgsControllerTriggerPressed> ControllerTriggerPressed = delegate { };
|
||||||
|
public static event EventHandler<EventArgsControllerTriggerReleased> ControllerTriggerReleased = delegate { };
|
||||||
|
|
||||||
|
public static void InvokeKeyboardChanged(KeyboardState priorState, KeyboardState newState)
|
||||||
|
{
|
||||||
|
KeyboardChanged.Invoke(null, new EventArgsKeyboardStateChanged(priorState, newState));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeMouseChanged(MouseState priorState, MouseState newState)
|
||||||
|
{
|
||||||
|
MouseChanged.Invoke(null, new EventArgsMouseStateChanged(priorState, newState));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeKeyPressed(Keys key)
|
||||||
|
{
|
||||||
|
KeyPressed.Invoke(null, new EventArgsKeyPressed(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeKeyReleased(Keys key)
|
||||||
|
{
|
||||||
|
KeyReleased.Invoke(null, new EventArgsKeyPressed(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeButtonPressed(PlayerIndex playerIndex, Buttons buttons)
|
||||||
|
{
|
||||||
|
ControllerButtonPressed.Invoke(null, new EventArgsControllerButtonPressed(playerIndex, buttons));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeButtonReleased(PlayerIndex playerIndex, Buttons buttons)
|
||||||
|
{
|
||||||
|
ControllerButtonReleased.Invoke(null, new EventArgsControllerButtonReleased(playerIndex, buttons));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeTriggerPressed(PlayerIndex playerIndex, Buttons buttons, float value)
|
||||||
|
{
|
||||||
|
ControllerTriggerPressed.Invoke(null, new EventArgsControllerTriggerPressed(playerIndex, buttons, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeTriggerReleased(PlayerIndex playerIndex, Buttons buttons, float value)
|
||||||
|
{
|
||||||
|
ControllerTriggerReleased.Invoke(null, new EventArgsControllerTriggerReleased(playerIndex, buttons, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using StardewModdingAPI.Inheritance;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public class EventArgsKeyboardStateChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsKeyboardStateChanged(KeyboardState priorState, KeyboardState newState)
|
||||||
|
{
|
||||||
|
NewState = newState;
|
||||||
|
NewState = newState;
|
||||||
|
}
|
||||||
|
public KeyboardState NewState { get; private set; }
|
||||||
|
public KeyboardState PriorState { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsKeyPressed : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsKeyPressed(Keys keyPressed)
|
||||||
|
{
|
||||||
|
KeyPressed = keyPressed;
|
||||||
|
}
|
||||||
|
public Keys KeyPressed { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsControllerButtonPressed : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsControllerButtonPressed(PlayerIndex playerIndex, Buttons buttonPressed)
|
||||||
|
{
|
||||||
|
PlayerIndex = playerIndex;
|
||||||
|
ButtonPressed = buttonPressed;
|
||||||
|
}
|
||||||
|
public PlayerIndex PlayerIndex { get; private set; }
|
||||||
|
public Buttons ButtonPressed { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsControllerButtonReleased : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsControllerButtonReleased(PlayerIndex playerIndex, Buttons buttonReleased)
|
||||||
|
{
|
||||||
|
PlayerIndex = playerIndex;
|
||||||
|
ButtonReleased = buttonReleased;
|
||||||
|
}
|
||||||
|
public PlayerIndex PlayerIndex { get; private set; }
|
||||||
|
public Buttons ButtonReleased { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsControllerTriggerPressed : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsControllerTriggerPressed(PlayerIndex playerIndex, Buttons buttonPressed, float value)
|
||||||
|
{
|
||||||
|
PlayerIndex = playerIndex;
|
||||||
|
ButtonPressed = buttonPressed;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
public PlayerIndex PlayerIndex { get; private set; }
|
||||||
|
public Buttons ButtonPressed { get; private set; }
|
||||||
|
public float Value { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsControllerTriggerReleased : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsControllerTriggerReleased(PlayerIndex playerIndex, Buttons buttonReleased, float value)
|
||||||
|
{
|
||||||
|
PlayerIndex = playerIndex;
|
||||||
|
ButtonReleased = buttonReleased;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
public PlayerIndex PlayerIndex { get; private set; }
|
||||||
|
public Buttons ButtonReleased { get; private set; }
|
||||||
|
public float Value { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsMouseStateChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsMouseStateChanged(MouseState priorState, MouseState newState)
|
||||||
|
{
|
||||||
|
NewState = newState;
|
||||||
|
NewState = newState;
|
||||||
|
}
|
||||||
|
public MouseState NewState { get; private set; }
|
||||||
|
public MouseState PriorState { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsClickableMenuChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsClickableMenuChanged(IClickableMenu priorMenu, IClickableMenu newMenu)
|
||||||
|
{
|
||||||
|
NewMenu = newMenu;
|
||||||
|
PriorMenu = priorMenu;
|
||||||
|
}
|
||||||
|
public IClickableMenu NewMenu { get; private set; }
|
||||||
|
public IClickableMenu PriorMenu { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsGameLocationsChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsGameLocationsChanged(List<GameLocation> newLocations)
|
||||||
|
{
|
||||||
|
NewLocations = newLocations;
|
||||||
|
}
|
||||||
|
public List<GameLocation> NewLocations { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsLocationObjectsChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsLocationObjectsChanged(SerializableDictionary<Vector2, StardewValley.Object> newObjects)
|
||||||
|
{
|
||||||
|
NewObjects = newObjects;
|
||||||
|
}
|
||||||
|
public SerializableDictionary<Vector2, StardewValley.Object> NewObjects { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsCurrentLocationChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsCurrentLocationChanged(GameLocation priorLocation, GameLocation newLocation)
|
||||||
|
{
|
||||||
|
NewLocation = newLocation;
|
||||||
|
PriorLocation = priorLocation;
|
||||||
|
}
|
||||||
|
public GameLocation NewLocation { get; private set; }
|
||||||
|
public GameLocation PriorLocation { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsFarmerChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsFarmerChanged(Farmer priorFarmer, Farmer newFarmer)
|
||||||
|
{
|
||||||
|
NewFarmer = NewFarmer;
|
||||||
|
PriorFarmer = PriorFarmer;
|
||||||
|
}
|
||||||
|
public Farmer NewFarmer { get; private set; }
|
||||||
|
public Farmer PriorFarmer { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsInventoryChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsInventoryChanged(List<Item> inventory, List<ItemStackChange> changedItems)
|
||||||
|
{
|
||||||
|
Inventory = inventory;
|
||||||
|
Added = changedItems.Where(n => n.ChangeType == ChangeType.Added).ToList();
|
||||||
|
Removed = changedItems.Where(n => n.ChangeType == ChangeType.Removed).ToList();
|
||||||
|
QuantityChanged = changedItems.Where(n => n.ChangeType == ChangeType.StackChange).ToList();
|
||||||
|
}
|
||||||
|
public List<Item> Inventory { get; private set; }
|
||||||
|
public List<ItemStackChange> Added { get; private set; }
|
||||||
|
public List<ItemStackChange> Removed { get; private set; }
|
||||||
|
public List<ItemStackChange> QuantityChanged { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsLevelUp : EventArgs
|
||||||
|
{
|
||||||
|
public enum LevelType
|
||||||
|
{
|
||||||
|
Combat,
|
||||||
|
Farming,
|
||||||
|
Fishing,
|
||||||
|
Foraging,
|
||||||
|
Mining,
|
||||||
|
Luck
|
||||||
|
}
|
||||||
|
public EventArgsLevelUp(LevelType type, Int32 newLevel)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
NewLevel = newLevel;
|
||||||
|
}
|
||||||
|
public LevelType Type { get; private set; }
|
||||||
|
public Int32 NewLevel { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsIntChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsIntChanged(Int32 priorInt, Int32 newInt)
|
||||||
|
{
|
||||||
|
NewInt = NewInt;
|
||||||
|
PriorInt = PriorInt;
|
||||||
|
}
|
||||||
|
public Int32 NewInt { get; private set; }
|
||||||
|
public Int32 PriorInt { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsStringChanged : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsStringChanged(String priorString, String newString)
|
||||||
|
{
|
||||||
|
NewString = newString;
|
||||||
|
PriorString = priorString;
|
||||||
|
}
|
||||||
|
public String NewString { get; private set; }
|
||||||
|
public String PriorString { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventArgsCommand : EventArgs
|
||||||
|
{
|
||||||
|
public EventArgsCommand(Command command)
|
||||||
|
{
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
public Command Command { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public class FarmAnimal
|
||||||
|
{
|
||||||
|
public void eatGrass_OnEnter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class GameEvents
|
||||||
|
{
|
||||||
|
public static event EventHandler GameLoaded = delegate { };
|
||||||
|
public static event EventHandler Initialize = delegate { };
|
||||||
|
public static event EventHandler LoadContent = delegate { };
|
||||||
|
public static event EventHandler UpdateTick = delegate { };
|
||||||
|
|
||||||
|
public static void InvokeGameLoaded()
|
||||||
|
{
|
||||||
|
GameLoaded.Invoke(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeInitialize()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Initialize.Invoke(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("An exception occured in XNA Initialize: " + ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeLoadContent()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LoadContent.Invoke(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("An exception occured in XNA LoadContent: " + ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeUpdateTick()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Program.IsGameReferenceDirty = true;
|
||||||
|
var test = Program.gamePtr;
|
||||||
|
UpdateTick.Invoke(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("An exception occured in XNA UpdateTick: " + ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class GraphicsEvents
|
||||||
|
{
|
||||||
|
public static event EventHandler Resize = delegate { };
|
||||||
|
public static event EventHandler DrawTick = delegate { };
|
||||||
|
|
||||||
|
public static void InvokeDrawTick()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DrawTick.Invoke(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("An exception occured in XNA DrawTick: " + ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeResize(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Resize.Invoke(sender, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using StardewValley;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class LocationEvents
|
||||||
|
{
|
||||||
|
public static event EventHandler<EventArgsGameLocationsChanged> LocationsChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsLocationObjectsChanged> LocationObjectsChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsCurrentLocationChanged> CurrentLocationChanged = delegate { };
|
||||||
|
|
||||||
|
public static void InvokeLocationsChanged(List<GameLocation> newLocations)
|
||||||
|
{
|
||||||
|
LocationsChanged.Invoke(null, new EventArgsGameLocationsChanged(newLocations));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeCurrentLocationChanged(GameLocation priorLocation, GameLocation newLocation)
|
||||||
|
{
|
||||||
|
CurrentLocationChanged.Invoke(null, new EventArgsCurrentLocationChanged(priorLocation, newLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void InvokeOnNewLocationObject(SerializableDictionary<Vector2, StardewValley.Object> newObjects)
|
||||||
|
{
|
||||||
|
LocationObjectsChanged.Invoke(null, new EventArgsLocationObjectsChanged(newObjects));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using StardewValley.Menus;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class MenuEvents
|
||||||
|
{
|
||||||
|
public static event EventHandler<EventArgsClickableMenuChanged> MenuChanged = delegate { };
|
||||||
|
|
||||||
|
public static void InvokeMenuChanged(IClickableMenu priorMenu, IClickableMenu newMenu)
|
||||||
|
{
|
||||||
|
MenuChanged.Invoke(null, new EventArgsClickableMenuChanged(priorMenu, newMenu));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class MineEvents
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using StardewModdingAPI.Inheritance;
|
||||||
|
using StardewValley;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class PlayerEvents
|
||||||
|
{
|
||||||
|
public static event EventHandler<EventArgsFarmerChanged> FarmerChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsInventoryChanged> InventoryChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsLevelUp> LeveledUp = delegate { };
|
||||||
|
|
||||||
|
public static void InvokeFarmerChanged(Farmer priorFarmer, Farmer newFarmer)
|
||||||
|
{
|
||||||
|
FarmerChanged.Invoke(null, new EventArgsFarmerChanged(priorFarmer, newFarmer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeInventoryChanged(List<Item> inventory, List<ItemStackChange> changedItems)
|
||||||
|
{
|
||||||
|
InventoryChanged.Invoke(null, new EventArgsInventoryChanged(inventory, changedItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeLeveledUp(EventArgsLevelUp.LevelType type, int newLevel)
|
||||||
|
{
|
||||||
|
LeveledUp.Invoke(null, new EventArgsLevelUp(type, newLevel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Events
|
||||||
|
{
|
||||||
|
public static class TimeEvents
|
||||||
|
{
|
||||||
|
public static event EventHandler<EventArgsIntChanged> TimeOfDayChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsIntChanged> DayOfMonthChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsIntChanged> YearOfGameChanged = delegate { };
|
||||||
|
public static event EventHandler<EventArgsStringChanged> SeasonOfYearChanged = delegate { };
|
||||||
|
|
||||||
|
public static void InvokeTimeOfDayChanged(Int32 priorInt, Int32 newInt)
|
||||||
|
{
|
||||||
|
TimeOfDayChanged.Invoke(null, new EventArgsIntChanged(priorInt, newInt));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeDayOfMonthChanged(Int32 priorInt, Int32 newInt)
|
||||||
|
{
|
||||||
|
DayOfMonthChanged.Invoke(null, new EventArgsIntChanged(priorInt, newInt));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeYearOfGameChanged(Int32 priorInt, Int32 newInt)
|
||||||
|
{
|
||||||
|
YearOfGameChanged.Invoke(null, new EventArgsIntChanged(priorInt, newInt));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InvokeSeasonOfYearChanged(String priorString, String newString)
|
||||||
|
{
|
||||||
|
SeasonOfYearChanged.Invoke(null, new EventArgsStringChanged(priorString, newString));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.ExtensionMethods
|
||||||
|
{
|
||||||
|
public static class ArrayExtensions
|
||||||
|
{
|
||||||
|
public static void ForEach(this Array array, Action<Array, int[]> action)
|
||||||
|
{
|
||||||
|
if (array.LongLength == 0) return;
|
||||||
|
ArrayTraverse walker = new ArrayTraverse(array);
|
||||||
|
do action(array, walker.Position);
|
||||||
|
while (walker.Step());
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static void ForEach(Array array, Action<Array, int[]> action)
|
||||||
|
//{
|
||||||
|
// if (array.LongLength == 0) return;
|
||||||
|
// ArrayTraverse walker = new ArrayTraverse(array);
|
||||||
|
// do action(array, walker.Position);
|
||||||
|
// while (walker.Step());
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ArrayTraverse
|
||||||
|
{
|
||||||
|
public int[] Position;
|
||||||
|
private int[] maxLengths;
|
||||||
|
|
||||||
|
public ArrayTraverse(Array array)
|
||||||
|
{
|
||||||
|
maxLengths = new int[array.Rank];
|
||||||
|
for (int i = 0; i < array.Rank; ++i)
|
||||||
|
{
|
||||||
|
maxLengths[i] = array.GetLength(i) - 1;
|
||||||
|
}
|
||||||
|
Position = new int[array.Rank];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Step()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Position.Length; ++i)
|
||||||
|
{
|
||||||
|
if (Position[i] < maxLengths[i])
|
||||||
|
{
|
||||||
|
Position[i]++;
|
||||||
|
for (int j = 0; j < i; j++)
|
||||||
|
{
|
||||||
|
Position[j] = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.ExtensionMethods
|
||||||
|
{
|
||||||
|
//From https://github.com/jpmikkers/net-object-deep-copy/blob/master/ObjectExtensions.cs
|
||||||
|
public static class ObjectExtensions
|
||||||
|
{
|
||||||
|
public static T Copy<T>(this object original)
|
||||||
|
{
|
||||||
|
return (T)new DeepCopyContext().InternalCopy(original, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DeepCopyContext
|
||||||
|
{
|
||||||
|
private static readonly Func<object, object> CloneMethod;
|
||||||
|
private readonly Dictionary<Object, Object> m_Visited;
|
||||||
|
private readonly Dictionary<Type, FieldInfo[]> m_NonShallowFieldCache;
|
||||||
|
|
||||||
|
static DeepCopyContext()
|
||||||
|
{
|
||||||
|
MethodInfo cloneMethod = typeof(Object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
var p1 = Expression.Parameter(typeof(object));
|
||||||
|
var body = Expression.Call(p1, cloneMethod);
|
||||||
|
CloneMethod = Expression.Lambda<Func<object, object>>(body, p1).Compile();
|
||||||
|
//Console.WriteLine("typeof(object) contains {0} nonshallow fields", NonShallowFields(typeof(object)).Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeepCopyContext()
|
||||||
|
{
|
||||||
|
m_Visited = new Dictionary<object, object>(new ReferenceEqualityComparer());
|
||||||
|
m_NonShallowFieldCache = new Dictionary<Type, FieldInfo[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPrimitive(Type type)
|
||||||
|
{
|
||||||
|
if (type.IsValueType && type.IsPrimitive) return true;
|
||||||
|
if (type == typeof(String)) return true;
|
||||||
|
if (type == typeof(Decimal)) return true;
|
||||||
|
if (type == typeof(DateTime)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object InternalCopy(Object originalObject, bool includeInObjectGraph)
|
||||||
|
{
|
||||||
|
if (originalObject == null) return null;
|
||||||
|
var typeToReflect = originalObject.GetType();
|
||||||
|
if (IsPrimitive(typeToReflect)) return originalObject;
|
||||||
|
|
||||||
|
if (typeof(XElement).IsAssignableFrom(typeToReflect)) return new XElement(originalObject as XElement);
|
||||||
|
if (typeof(Delegate).IsAssignableFrom(typeToReflect)) return null;
|
||||||
|
|
||||||
|
if (includeInObjectGraph)
|
||||||
|
{
|
||||||
|
object result;
|
||||||
|
if (m_Visited.TryGetValue(originalObject, out result)) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cloneObject = CloneMethod(originalObject);
|
||||||
|
|
||||||
|
if (includeInObjectGraph)
|
||||||
|
{
|
||||||
|
m_Visited.Add(originalObject, cloneObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeToReflect.IsArray)
|
||||||
|
{
|
||||||
|
var arrayElementType = typeToReflect.GetElementType();
|
||||||
|
|
||||||
|
if (IsPrimitive(arrayElementType))
|
||||||
|
{
|
||||||
|
// for an array of primitives, do nothing. The shallow clone is enough.
|
||||||
|
}
|
||||||
|
else if (arrayElementType.IsValueType)
|
||||||
|
{
|
||||||
|
// if its an array of structs, there's no need to check and add the individual elements to 'visited', because in .NET it's impossible to create
|
||||||
|
// references to individual array elements.
|
||||||
|
Array clonedArray = (Array)cloneObject;
|
||||||
|
clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), false), indices));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// it's an array of ref types
|
||||||
|
Array clonedArray = (Array)cloneObject;
|
||||||
|
clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), true), indices));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var fieldInfo in CachedNonShallowFields(typeToReflect))
|
||||||
|
{
|
||||||
|
var originalFieldValue = fieldInfo.GetValue(originalObject);
|
||||||
|
// a valuetype field can never have a reference pointing to it, so don't check the object graph in that case
|
||||||
|
|
||||||
|
Log.Error("Replace this with a recurse-less version");
|
||||||
|
var clonedFieldValue = InternalCopy(originalFieldValue, !fieldInfo.FieldType.IsValueType);
|
||||||
|
fieldInfo.SetValue(cloneObject, clonedFieldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloneObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldInfo[] CachedNonShallowFields(Type typeToReflect)
|
||||||
|
{
|
||||||
|
FieldInfo[] result;
|
||||||
|
|
||||||
|
if (!m_NonShallowFieldCache.TryGetValue(typeToReflect, out result))
|
||||||
|
{
|
||||||
|
result = NonShallowFields(typeToReflect).ToArray();
|
||||||
|
m_NonShallowFieldCache[typeToReflect] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// From the given type hierarchy (i.e. including all base types), return all fields that should be deep-copied
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeToReflect"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static IEnumerable<FieldInfo> NonShallowFields(Type typeToReflect)
|
||||||
|
{
|
||||||
|
while (typeToReflect != typeof(object))
|
||||||
|
{
|
||||||
|
foreach (var fieldInfo in typeToReflect.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly))
|
||||||
|
{
|
||||||
|
if (IsPrimitive(fieldInfo.FieldType)) continue; // this is 5% faster than a where clause..
|
||||||
|
yield return fieldInfo;
|
||||||
|
}
|
||||||
|
typeToReflect = typeToReflect.BaseType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReferenceEqualityComparer : EqualityComparer<Object>
|
||||||
|
{
|
||||||
|
public override bool Equals(object x, object y)
|
||||||
|
{
|
||||||
|
return ReferenceEquals(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode(object obj)
|
||||||
|
{
|
||||||
|
if (obj == null) return 0;
|
||||||
|
// The RuntimeHelpers.GetHashCode method always calls the Object.GetHashCode method non-virtually,
|
||||||
|
// even if the object's type has overridden the Object.GetHashCode method.
|
||||||
|
return RuntimeHelpers.GetHashCode(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static Random Random = new Random();
|
||||||
|
|
||||||
|
public static bool IsKeyDown(this Keys key)
|
||||||
|
{
|
||||||
|
return Keyboard.GetState().IsKeyDown(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color RandomColour()
|
||||||
|
{
|
||||||
|
return new Color(Random.Next(0, 255), Random.Next(0, 255), Random.Next(0, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToSingular(this IEnumerable<Object> enumerable, string split = ", ")
|
||||||
|
{
|
||||||
|
string result = string.Join(split, enumerable);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInt32(this object o)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
return Int32.TryParse(o.ToString(), out i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int32 AsInt32(this object o)
|
||||||
|
{
|
||||||
|
return Int32.Parse(o.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsBool(this object o)
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
return Boolean.TryParse(o.ToString(), out b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AsBool(this object o)
|
||||||
|
{
|
||||||
|
return Boolean.Parse(o.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetHash(this IEnumerable enumerable)
|
||||||
|
{
|
||||||
|
int hash = 0;
|
||||||
|
foreach (var v in enumerable)
|
||||||
|
{
|
||||||
|
hash ^= v.GetHashCode();
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Helpers
|
||||||
|
{
|
||||||
|
public enum CecilContextType
|
||||||
|
{
|
||||||
|
SMAPI,
|
||||||
|
Stardew
|
||||||
|
}
|
||||||
|
public class CecilContext
|
||||||
|
{
|
||||||
|
public CecilContextType ContextType { get; private set;}
|
||||||
|
|
||||||
|
private AssemblyDefinition _assemblyDefinition { get; set; }
|
||||||
|
private bool _isMemoryStreamDirty { get; set; }
|
||||||
|
|
||||||
|
private MemoryStream _modifiedAssembly;
|
||||||
|
public MemoryStream ModifiedAssembly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_modifiedAssembly == null)
|
||||||
|
{
|
||||||
|
_modifiedAssembly = new MemoryStream();
|
||||||
|
_assemblyDefinition.Write(_modifiedAssembly);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_isMemoryStreamDirty)
|
||||||
|
{
|
||||||
|
_modifiedAssembly.Dispose();
|
||||||
|
_modifiedAssembly = new MemoryStream();
|
||||||
|
_assemblyDefinition.Write(_modifiedAssembly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _modifiedAssembly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CecilContext(CecilContextType contextType)
|
||||||
|
{
|
||||||
|
ContextType = contextType;
|
||||||
|
if (ContextType == CecilContextType.SMAPI)
|
||||||
|
_assemblyDefinition = AssemblyDefinition.ReadAssembly(Assembly.GetExecutingAssembly().Location);
|
||||||
|
else
|
||||||
|
_assemblyDefinition = AssemblyDefinition.ReadAssembly(Constants.StardewExePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILProcessor GetMethodILProcessor(string type, string method)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(type) || string.IsNullOrWhiteSpace(method))
|
||||||
|
throw new ArgumentNullException("Both type and method must be set");
|
||||||
|
|
||||||
|
Mono.Cecil.Cil.ILProcessor ilProcessor = null;
|
||||||
|
TypeDefinition typeDef = GetTypeDefinition(type);
|
||||||
|
if (typeDef != null)
|
||||||
|
{
|
||||||
|
MethodDefinition methodDef = typeDef.Methods.FirstOrDefault(m => m.Name == method);
|
||||||
|
if (methodDef != null)
|
||||||
|
{
|
||||||
|
ilProcessor = methodDef.Body.GetILProcessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ilProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeDefinition GetTypeDefinition(string type)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(type))
|
||||||
|
throw new ArgumentNullException("Both type and method must be set");
|
||||||
|
|
||||||
|
TypeDefinition typeDef = _assemblyDefinition.MainModule.Types.FirstOrDefault(n => n.FullName == type);
|
||||||
|
return typeDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDefinition GetMethodDefinition(string type, string method)
|
||||||
|
{
|
||||||
|
MethodDefinition methodDef = null;
|
||||||
|
TypeDefinition typeDef = GetTypeDefinition(type);
|
||||||
|
|
||||||
|
if (typeDef != null)
|
||||||
|
{
|
||||||
|
methodDef = typeDef.Methods.FirstOrDefault(m => m.Name == method);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstructorInfo GetSMAPITypeContructor(string type)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (ContextType != CecilContextType.SMAPI)
|
||||||
|
throw new Exception("GetSMAPIMethodReference can only be called on the SMAPI context");
|
||||||
|
|
||||||
|
ConstructorInfo methodInfo = null;
|
||||||
|
|
||||||
|
var reflectionType = Assembly.GetExecutingAssembly().GetType(type);
|
||||||
|
if (reflectionType != null)
|
||||||
|
{
|
||||||
|
methodInfo = reflectionType.GetConstructor(Type.EmptyTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodInfo GetSMAPIMethodReference(string type, string method)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (ContextType != CecilContextType.SMAPI)
|
||||||
|
throw new Exception("GetSMAPIMethodReference can only be called on the SMAPI context");
|
||||||
|
|
||||||
|
MethodInfo methodInfo = null;
|
||||||
|
|
||||||
|
var reflectionType = Assembly.GetExecutingAssembly().GetType(type);
|
||||||
|
if (reflectionType != null)
|
||||||
|
{
|
||||||
|
methodInfo = reflectionType.GetMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodReference ImportSMAPIMethodInStardew(CecilContext destinationContext, MethodBase method)
|
||||||
|
{
|
||||||
|
if (_assemblyDefinition == null)
|
||||||
|
throw new Exception("ERROR Assembly not properly read. Cannot parse");
|
||||||
|
|
||||||
|
if (ContextType != CecilContextType.SMAPI)
|
||||||
|
throw new Exception("ImportSmapiMethodInStardew can only be called on the Stardew context");
|
||||||
|
|
||||||
|
MethodReference reference = null;
|
||||||
|
if (method != null)
|
||||||
|
{
|
||||||
|
reference = destinationContext._assemblyDefinition.MainModule.Import(method);
|
||||||
|
}
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteAssembly(string file)
|
||||||
|
{
|
||||||
|
_assemblyDefinition.Write(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using Mono.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Helpers
|
||||||
|
{
|
||||||
|
public static class CecilHelper
|
||||||
|
{
|
||||||
|
//System.Void StardewValley.Game1::.ctor()
|
||||||
|
|
||||||
|
private static void InjectMethod(ILProcessor ilProcessor, Instruction target, MethodReference method)
|
||||||
|
{
|
||||||
|
Instruction callEnterInstruction = ilProcessor.Create(OpCodes.Call, method);
|
||||||
|
|
||||||
|
if(method.HasThis)
|
||||||
|
{
|
||||||
|
Instruction loadObjInstruction = ilProcessor.Create(OpCodes.Ldarg_0);
|
||||||
|
ilProcessor.InsertBefore(target, loadObjInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.HasParameters)
|
||||||
|
{
|
||||||
|
Instruction loadObjInstruction = ilProcessor.Create(OpCodes.Ldarg_0);
|
||||||
|
ilProcessor.InsertBefore(target, loadObjInstruction);
|
||||||
|
ilProcessor.InsertAfter(loadObjInstruction, callEnterInstruction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ilProcessor.InsertBefore(target, callEnterInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InjectMethod(ILProcessor ilProcessor, IEnumerable<Instruction> targets, MethodReference method)
|
||||||
|
{
|
||||||
|
foreach(var target in targets.ToList())
|
||||||
|
{
|
||||||
|
InjectMethod(ilProcessor, target, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Instruction> GetMatchingInstructions(Collection<Instruction> instructions, OpCode opcode, object @object)
|
||||||
|
{
|
||||||
|
return instructions.Where(n => n.OpCode == opcode && n.Operand == @object).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RedirectConstructor(CecilContext stardewContext, CecilContext smapiContext,
|
||||||
|
string typeToAlter, string methodToAlter,
|
||||||
|
string injecteeType, string injecteeMethod,
|
||||||
|
string injectedType, string injectedMethod)
|
||||||
|
{
|
||||||
|
var ilProcessor = stardewContext.GetMethodILProcessor(typeToAlter, methodToAlter);
|
||||||
|
var methodDefinition = stardewContext.GetMethodDefinition(injecteeType, injecteeMethod);
|
||||||
|
|
||||||
|
var methodInfo = smapiContext.GetSMAPITypeContructor(injectedType);
|
||||||
|
var reference = smapiContext.ImportSMAPIMethodInStardew(stardewContext, methodInfo);
|
||||||
|
|
||||||
|
var instructionsToAlter = GetMatchingInstructions(ilProcessor.Body.Instructions, OpCodes.Newobj, methodDefinition);
|
||||||
|
|
||||||
|
var newInstruction = ilProcessor.Create(OpCodes.Newobj, reference);
|
||||||
|
foreach(var instruction in instructionsToAlter)
|
||||||
|
{
|
||||||
|
ilProcessor.Replace(instruction, newInstruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void ReplaceInstruction(ILProcessor processor, OpCode opcode, string oldOperand, string newOperand)
|
||||||
|
//{
|
||||||
|
//var instructions = processor.Body.Instructions.Where(i => i.OpCode == opcode && i.Operand == oldOperand);
|
||||||
|
// processor.Create()
|
||||||
|
//}
|
||||||
|
|
||||||
|
public static void InjectEntryMethod(CecilContext stardewContext, CecilContext smapiContext, string injecteeType, string injecteeMethod,
|
||||||
|
string injectedType, string injectedMethod)
|
||||||
|
{
|
||||||
|
var methodInfo = smapiContext.GetSMAPIMethodReference(injectedType, injectedMethod);
|
||||||
|
var reference = smapiContext.ImportSMAPIMethodInStardew(stardewContext, methodInfo);
|
||||||
|
var ilProcessor = stardewContext.GetMethodILProcessor(injecteeType, injecteeMethod);
|
||||||
|
InjectMethod(ilProcessor, ilProcessor.Body.Instructions.First(), reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InjectExitMethod(CecilContext stardewContext, CecilContext smapiContext, string injecteeType, string injecteeMethod,
|
||||||
|
string injectedType, string injectedMethod)
|
||||||
|
{
|
||||||
|
var methodInfo = smapiContext.GetSMAPIMethodReference(injectedType, injectedMethod);
|
||||||
|
var reference = smapiContext.ImportSMAPIMethodInStardew(stardewContext, methodInfo);
|
||||||
|
var ilProcessor = stardewContext.GetMethodILProcessor(injecteeType, injecteeMethod);
|
||||||
|
InjectMethod(ilProcessor, ilProcessor.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret), reference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Helpers
|
||||||
|
{
|
||||||
|
public static class ReflectionHelper
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Helpers
|
||||||
|
{
|
||||||
|
public static class StardewAssembly
|
||||||
|
{
|
||||||
|
private static Assembly ModifiedGameAssembly { get; set; }
|
||||||
|
private static CecilContext StardewContext { get; set; }
|
||||||
|
private static CecilContext SmapiContext { get; set; }
|
||||||
|
|
||||||
|
public static void ModifyStardewAssembly()
|
||||||
|
{
|
||||||
|
StardewContext = new CecilContext(CecilContextType.Stardew);
|
||||||
|
SmapiContext = new CecilContext(CecilContextType.SMAPI);
|
||||||
|
|
||||||
|
CecilHelper.InjectEntryMethod(StardewContext, SmapiContext, "StardewValley.Game1", ".ctor", "StardewModdingAPI.Program", "Test");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "Initialize", "StardewModdingAPI.Events.GameEvents", "InvokeInitialize");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "LoadContent", "StardewModdingAPI.Events.GameEvents", "InvokeLoadContent");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "Update", "StardewModdingAPI.Events.GameEvents", "InvokeUpdateTick");
|
||||||
|
CecilHelper.InjectExitMethod(StardewContext, SmapiContext, "StardewValley.Game1", "Draw", "StardewModdingAPI.Events.GraphicsEvents", "InvokeDrawTick");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LoadStardewAssembly()
|
||||||
|
{
|
||||||
|
ModifiedGameAssembly = Assembly.Load(StardewContext.ModifiedAssembly.GetBuffer());
|
||||||
|
//ModifiedGameAssembly = Assembly.UnsafeLoadFrom(Constants.ExecutionPath + "\\Stardew Valley.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Launch()
|
||||||
|
{
|
||||||
|
ModifiedGameAssembly.EntryPoint.Invoke(null, new object[] { new string[] { } });
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void WriteModifiedExe()
|
||||||
|
{
|
||||||
|
StardewContext.WriteAssembly("StardewValley-Modified.exe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using StardewValley;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance
|
||||||
|
{
|
||||||
|
public enum ChangeType
|
||||||
|
{
|
||||||
|
Removed,
|
||||||
|
Added,
|
||||||
|
StackChange
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ItemStackChange
|
||||||
|
{
|
||||||
|
public Item Item { get; set; }
|
||||||
|
public int StackChange { get; set; }
|
||||||
|
public ChangeType ChangeType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,298 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using StardewValley.BellsAndWhistles;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance.Menus
|
||||||
|
{
|
||||||
|
public class SBobberBar : BobberBar
|
||||||
|
{
|
||||||
|
public BobberBar BaseBobberBar { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The green rectangle bar that moves up and down
|
||||||
|
/// </summary>
|
||||||
|
public float bobberPosition
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("bobberPosition").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberPosition").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The green bar on the right. How close to catching the fish you are
|
||||||
|
/// Range: 0 - 1 | 1 = catch, 0 = fail
|
||||||
|
/// </summary>
|
||||||
|
public float distanceFromCatching
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("distanceFromCatching").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("distanceFromCatching").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float difficulty
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("difficulty").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("difficulty").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int motionType
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("motionType").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("motionType").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int whichFish
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("whichFish").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("whichFish").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float bobberSpeed
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("bobberSpeed").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberSpeed").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float bobberAcceleration
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("bobberAcceleration").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberAcceleration").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float bobberTargetPosition
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("bobberTargetPosition").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberTargetPosition").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float scale
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("scale").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("scale").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float everythingShakeTimer
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("everythingShakeTimer").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("everythingShakeTimer").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float floaterSinkerAcceleration
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("floaterSinkerAcceleration").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("floaterSinkerAcceleration").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float treasurePosition
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("treasurePosition").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("treasurePosition").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float treasureCatchLevel
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("treasureCatchLevel").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("treasureCatchLevel").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float treasureAppearTimer
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("treasureAppearTimer").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("treasureAppearTimer").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float treasureScale
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("treasureScale").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("treasureScale").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool bobberInBar
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("bobberInBar").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberInBar").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool buttonPressed
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("buttonPressed").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("buttonPressed").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool flipBubble
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("flipBubble").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("flipBubble").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool fadeIn
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("fadeIn").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("fadeIn").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool fadeOut
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("fadeOut").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberPfadeOutosition").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not a treasure chest appears
|
||||||
|
/// </summary>
|
||||||
|
public bool treasure
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("treasure").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("treasure").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool treasureCaught
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("treasureCaught").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("treasureCaught").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool perfect
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("perfect").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("perfect").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool bossFish
|
||||||
|
{
|
||||||
|
get { return (bool) GetBaseFieldInfo("bossFish").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bossFish").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int bobberBarHeight
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("bobberBarHeight").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberBarHeight").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fishSize
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("fishSize").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("fishSize").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fishQuality
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("fishQuality").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("fishQuality").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int minFishSize
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("minFishSize").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("minFishSize").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int maxFishSize
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("maxFishSize").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("maxFishSize").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fishSizeReductionTimer
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("fishSizeReductionTimer").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("fishSizeReductionTimer").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int whichBobber
|
||||||
|
{
|
||||||
|
get { return (int) GetBaseFieldInfo("whichBobber").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("whichBobber").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 barShake
|
||||||
|
{
|
||||||
|
get { return (Vector2) GetBaseFieldInfo("barShake").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("barShake").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 fishShake
|
||||||
|
{
|
||||||
|
get { return (Vector2) GetBaseFieldInfo("fishShake").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("fishShake").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 everythingShake
|
||||||
|
{
|
||||||
|
get { return (Vector2) GetBaseFieldInfo("everythingShake").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("everythingShake").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 treasureShake
|
||||||
|
{
|
||||||
|
get { return (Vector2) GetBaseFieldInfo("treasureShake").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("treasureShake").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float reelRotation
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("reelRotation").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("reelRotation").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public SparklingText sparkleText
|
||||||
|
{
|
||||||
|
get { return (SparklingText) GetBaseFieldInfo("sparkleText").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("sparkleText").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float bobberBarPos
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("bobberBarPos").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberBarPos").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float bobberBarSpeed
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("bobberBarSpeed").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberBarSpeed").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float bobberBarAcceleration
|
||||||
|
{
|
||||||
|
get { return (float) GetBaseFieldInfo("bobberBarAcceleration").GetValue(BaseBobberBar); }
|
||||||
|
set { GetBaseFieldInfo("bobberBarAcceleration").SetValue(BaseBobberBar, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldInfo[] PrivateFields
|
||||||
|
{
|
||||||
|
get { return GetPrivateFields(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SBobberBar ConstructFromBaseClass(BobberBar baseClass)
|
||||||
|
{
|
||||||
|
SBobberBar b = new SBobberBar(0, 0, false, 0);
|
||||||
|
b.BaseBobberBar = baseClass;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DO NOT CONSTRUCT THIS CLASS
|
||||||
|
/// To retrieve an instance of SBobberBar, use SBobberBar.ConstructFromBaseClass()
|
||||||
|
/// </summary>
|
||||||
|
public SBobberBar(int whichFish, float fishSize, bool treasure, int bobber) : base(whichFish, fishSize, treasure, bobber)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldInfo[] GetPrivateFields()
|
||||||
|
{
|
||||||
|
return typeof (BobberBar).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldInfo GetBaseFieldInfo(string name)
|
||||||
|
{
|
||||||
|
return typeof (BobberBar).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.Eventing.Reader;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance.Menus
|
||||||
|
{
|
||||||
|
public class SGameMenu : StardewValley.Menus.GameMenu
|
||||||
|
{
|
||||||
|
public GameMenu BaseGameMenu { get; private set; }
|
||||||
|
|
||||||
|
public List<ClickableComponent> tabs
|
||||||
|
{
|
||||||
|
get { return (List<ClickableComponent>)GetBaseFieldInfo("tabs").GetValue(BaseGameMenu); }
|
||||||
|
set { GetBaseFieldInfo("tabs").SetValue(BaseGameMenu, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IClickableMenu> pages
|
||||||
|
{
|
||||||
|
get { return (List<IClickableMenu>)GetBaseFieldInfo("pages").GetValue(BaseGameMenu); }
|
||||||
|
set { GetBaseFieldInfo("pages").SetValue(BaseGameMenu, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SGameMenu ConstructFromBaseClass(GameMenu baseClass)
|
||||||
|
{
|
||||||
|
SGameMenu s = new SGameMenu();
|
||||||
|
s.BaseGameMenu = baseClass;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void receiveRightClick(int x, int y, bool playSound = true)
|
||||||
|
{
|
||||||
|
if (pages[currentTab] is InventoryPage)
|
||||||
|
{
|
||||||
|
Log.Verbose("INV SCREEN");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
base.receiveRightClick(x, y, playSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldInfo[] GetPrivateFields()
|
||||||
|
{
|
||||||
|
return typeof(GameMenu).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldInfo GetBaseFieldInfo(string name)
|
||||||
|
{
|
||||||
|
return typeof(GameMenu).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance.Menus
|
||||||
|
{
|
||||||
|
public class SInventoryPage : InventoryPage
|
||||||
|
{
|
||||||
|
public InventoryPage BaseInventoryPage { get; private set; }
|
||||||
|
|
||||||
|
public static SInventoryPage ConstructFromBaseClass(InventoryPage baseClass)
|
||||||
|
{
|
||||||
|
SInventoryPage s = new SInventoryPage(0,0,0,0);
|
||||||
|
s.BaseInventoryPage = baseClass;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SInventoryPage(int x, int y, int width, int height) : base(x, y, width, height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance.Minigames
|
||||||
|
{
|
||||||
|
abstract class SMinigameBase : StardewValley.Minigames.IMinigame
|
||||||
|
{
|
||||||
|
public abstract bool tick(GameTime time);
|
||||||
|
|
||||||
|
public abstract void receiveLeftClick(int x, int y, bool playSound = true);
|
||||||
|
|
||||||
|
public abstract void leftClickHeld(int x, int y);
|
||||||
|
|
||||||
|
public abstract void receiveRightClick(int x, int y, bool playSound = true);
|
||||||
|
|
||||||
|
public abstract void releaseLeftClick(int x, int y);
|
||||||
|
|
||||||
|
public abstract void releaseRightClick(int x, int y);
|
||||||
|
|
||||||
|
public abstract void receiveKeyPress(Keys k);
|
||||||
|
|
||||||
|
public abstract void receiveKeyRelease(Keys k);
|
||||||
|
|
||||||
|
public abstract void draw(SpriteBatch b);
|
||||||
|
|
||||||
|
public abstract void changeScreenSize();
|
||||||
|
|
||||||
|
public abstract void unload();
|
||||||
|
|
||||||
|
public abstract void receiveEventPoke(int data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,497 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Characters;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
using StardewValley.Monsters;
|
||||||
|
using StardewValley.Quests;
|
||||||
|
using StardewValley.TerrainFeatures;
|
||||||
|
using StardewModdingAPI.Events;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance
|
||||||
|
{
|
||||||
|
public class SGame : Game1
|
||||||
|
{
|
||||||
|
public static List<SGameLocation> ModLocations = new List<SGameLocation>();
|
||||||
|
public static SGameLocation CurrentLocation { get; internal set; }
|
||||||
|
public static Dictionary<Int32, SObject> ModItems { get; private set; }
|
||||||
|
public const Int32 LowestModItemID = 1000;
|
||||||
|
|
||||||
|
public static FieldInfo[] StaticFields { get { return GetStaticFields(); } }
|
||||||
|
|
||||||
|
public static FieldInfo[] GetStaticFields()
|
||||||
|
{
|
||||||
|
return typeof(Game1).GetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyboardState KStateNow { get; private set; }
|
||||||
|
public KeyboardState KStatePrior { get; private set; }
|
||||||
|
|
||||||
|
public MouseState MStateNow { get; private set; }
|
||||||
|
public MouseState MStatePrior { get; private set; }
|
||||||
|
|
||||||
|
public Keys[] CurrentlyPressedKeys { get; private set; }
|
||||||
|
public Keys[] PreviouslyPressedKeys { get; private set; }
|
||||||
|
|
||||||
|
public Keys[] FramePressedKeys
|
||||||
|
{
|
||||||
|
get { return CurrentlyPressedKeys.Where(x => !PreviouslyPressedKeys.Contains(x)).ToArray(); }
|
||||||
|
}
|
||||||
|
public Keys[] FrameReleasedKeys
|
||||||
|
{
|
||||||
|
get { return PreviouslyPressedKeys.Where(x => !CurrentlyPressedKeys.Contains(x)).ToArray(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buttons[][] PreviouslyPressedButtons;
|
||||||
|
|
||||||
|
private bool WasButtonJustPressed(Buttons button, ButtonState buttonState, PlayerIndex stateIndex)
|
||||||
|
{
|
||||||
|
return buttonState == ButtonState.Pressed && !PreviouslyPressedButtons[(int)stateIndex].Contains(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool WasButtonJustReleased(Buttons button, ButtonState buttonState, PlayerIndex stateIndex)
|
||||||
|
{
|
||||||
|
return buttonState == ButtonState.Released && PreviouslyPressedButtons[(int)stateIndex].Contains(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool WasButtonJustPressed(Buttons button, float value, PlayerIndex stateIndex)
|
||||||
|
{
|
||||||
|
return WasButtonJustPressed(button, value > 0.2f ? ButtonState.Pressed : ButtonState.Released, stateIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool WasButtonJustReleased(Buttons button, float value, PlayerIndex stateIndex)
|
||||||
|
{
|
||||||
|
return WasButtonJustReleased(button, value > 0.2f ? ButtonState.Pressed : ButtonState.Released, stateIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buttons[] GetButtonsDown(PlayerIndex index)
|
||||||
|
{
|
||||||
|
GamePadState state = GamePad.GetState((PlayerIndex)index);
|
||||||
|
List<Buttons> buttons = new List<Buttons>();
|
||||||
|
if (state.IsConnected)
|
||||||
|
{
|
||||||
|
if (state.Buttons.A == ButtonState.Pressed) buttons.Add(Buttons.A);
|
||||||
|
if (state.Buttons.B == ButtonState.Pressed) buttons.Add(Buttons.B);
|
||||||
|
if (state.Buttons.Back == ButtonState.Pressed) buttons.Add(Buttons.Back);
|
||||||
|
if (state.Buttons.BigButton == ButtonState.Pressed) buttons.Add(Buttons.BigButton);
|
||||||
|
if (state.Buttons.LeftShoulder == ButtonState.Pressed) buttons.Add(Buttons.LeftShoulder);
|
||||||
|
if (state.Buttons.LeftStick == ButtonState.Pressed) buttons.Add(Buttons.LeftStick);
|
||||||
|
if (state.Buttons.RightShoulder == ButtonState.Pressed) buttons.Add(Buttons.RightShoulder);
|
||||||
|
if (state.Buttons.RightStick == ButtonState.Pressed) buttons.Add(Buttons.RightStick);
|
||||||
|
if (state.Buttons.Start == ButtonState.Pressed) buttons.Add(Buttons.Start);
|
||||||
|
if (state.Buttons.X == ButtonState.Pressed) buttons.Add(Buttons.X);
|
||||||
|
if (state.Buttons.Y == ButtonState.Pressed) buttons.Add(Buttons.Y);
|
||||||
|
if (state.DPad.Up == ButtonState.Pressed) buttons.Add(Buttons.DPadUp);
|
||||||
|
if (state.DPad.Down == ButtonState.Pressed) buttons.Add(Buttons.DPadDown);
|
||||||
|
if (state.DPad.Left == ButtonState.Pressed) buttons.Add(Buttons.DPadLeft);
|
||||||
|
if (state.DPad.Right == ButtonState.Pressed) buttons.Add(Buttons.DPadRight);
|
||||||
|
if (state.Triggers.Left > 0.2f) buttons.Add(Buttons.LeftTrigger);
|
||||||
|
if (state.Triggers.Right > 0.2f) buttons.Add(Buttons.RightTrigger);
|
||||||
|
}
|
||||||
|
return buttons.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buttons[] GetFramePressedButtons(PlayerIndex index)
|
||||||
|
{
|
||||||
|
GamePadState state = GamePad.GetState((PlayerIndex)index);
|
||||||
|
List<Buttons> buttons = new List<Buttons>();
|
||||||
|
if (state.IsConnected)
|
||||||
|
{
|
||||||
|
if (WasButtonJustPressed(Buttons.A, state.Buttons.A, index)) buttons.Add(Buttons.A);
|
||||||
|
if (WasButtonJustPressed(Buttons.B, state.Buttons.B, index)) buttons.Add(Buttons.B);
|
||||||
|
if (WasButtonJustPressed(Buttons.Back, state.Buttons.Back, index)) buttons.Add(Buttons.Back);
|
||||||
|
if (WasButtonJustPressed(Buttons.BigButton, state.Buttons.BigButton, index)) buttons.Add(Buttons.BigButton);
|
||||||
|
if (WasButtonJustPressed(Buttons.LeftShoulder, state.Buttons.LeftShoulder, index)) buttons.Add(Buttons.LeftShoulder);
|
||||||
|
if (WasButtonJustPressed(Buttons.LeftStick, state.Buttons.LeftStick, index)) buttons.Add(Buttons.LeftStick);
|
||||||
|
if (WasButtonJustPressed(Buttons.RightShoulder, state.Buttons.RightShoulder, index)) buttons.Add(Buttons.RightShoulder);
|
||||||
|
if (WasButtonJustPressed(Buttons.RightStick, state.Buttons.RightStick, index)) buttons.Add(Buttons.RightStick);
|
||||||
|
if (WasButtonJustPressed(Buttons.Start, state.Buttons.Start, index)) buttons.Add(Buttons.Start);
|
||||||
|
if (WasButtonJustPressed(Buttons.X, state.Buttons.X, index)) buttons.Add(Buttons.X);
|
||||||
|
if (WasButtonJustPressed(Buttons.Y, state.Buttons.Y, index)) buttons.Add(Buttons.Y);
|
||||||
|
if (WasButtonJustPressed(Buttons.DPadUp, state.DPad.Up, index)) buttons.Add(Buttons.DPadUp);
|
||||||
|
if (WasButtonJustPressed(Buttons.DPadDown, state.DPad.Down, index)) buttons.Add(Buttons.DPadDown);
|
||||||
|
if (WasButtonJustPressed(Buttons.DPadLeft, state.DPad.Left, index)) buttons.Add(Buttons.DPadLeft);
|
||||||
|
if (WasButtonJustPressed(Buttons.DPadRight, state.DPad.Right, index)) buttons.Add(Buttons.DPadRight);
|
||||||
|
if (WasButtonJustPressed(Buttons.LeftTrigger, state.Triggers.Left, index)) buttons.Add(Buttons.LeftTrigger);
|
||||||
|
if (WasButtonJustPressed(Buttons.RightTrigger, state.Triggers.Right, index)) buttons.Add(Buttons.RightTrigger);
|
||||||
|
}
|
||||||
|
return buttons.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Buttons[] GetFrameReleasedButtons(PlayerIndex index)
|
||||||
|
{
|
||||||
|
GamePadState state = GamePad.GetState((PlayerIndex)index);
|
||||||
|
List<Buttons> buttons = new List<Buttons>();
|
||||||
|
if (state.IsConnected)
|
||||||
|
{
|
||||||
|
if (WasButtonJustReleased(Buttons.A, state.Buttons.A, index)) buttons.Add(Buttons.A);
|
||||||
|
if (WasButtonJustReleased(Buttons.B, state.Buttons.B, index)) buttons.Add(Buttons.B);
|
||||||
|
if (WasButtonJustReleased(Buttons.Back, state.Buttons.Back, index)) buttons.Add(Buttons.Back);
|
||||||
|
if (WasButtonJustReleased(Buttons.BigButton, state.Buttons.BigButton, index)) buttons.Add(Buttons.BigButton);
|
||||||
|
if (WasButtonJustReleased(Buttons.LeftShoulder, state.Buttons.LeftShoulder, index)) buttons.Add(Buttons.LeftShoulder);
|
||||||
|
if (WasButtonJustReleased(Buttons.LeftStick, state.Buttons.LeftStick, index)) buttons.Add(Buttons.LeftStick);
|
||||||
|
if (WasButtonJustReleased(Buttons.RightShoulder, state.Buttons.RightShoulder, index)) buttons.Add(Buttons.RightShoulder);
|
||||||
|
if (WasButtonJustReleased(Buttons.RightStick, state.Buttons.RightStick, index)) buttons.Add(Buttons.RightStick);
|
||||||
|
if (WasButtonJustReleased(Buttons.Start, state.Buttons.Start, index)) buttons.Add(Buttons.Start);
|
||||||
|
if (WasButtonJustReleased(Buttons.X, state.Buttons.X, index)) buttons.Add(Buttons.X);
|
||||||
|
if (WasButtonJustReleased(Buttons.Y, state.Buttons.Y, index)) buttons.Add(Buttons.Y);
|
||||||
|
if (WasButtonJustReleased(Buttons.DPadUp, state.DPad.Up, index)) buttons.Add(Buttons.DPadUp);
|
||||||
|
if (WasButtonJustReleased(Buttons.DPadDown, state.DPad.Down, index)) buttons.Add(Buttons.DPadDown);
|
||||||
|
if (WasButtonJustReleased(Buttons.DPadLeft, state.DPad.Left, index)) buttons.Add(Buttons.DPadLeft);
|
||||||
|
if (WasButtonJustReleased(Buttons.DPadRight, state.DPad.Right, index)) buttons.Add(Buttons.DPadRight);
|
||||||
|
if (WasButtonJustReleased(Buttons.LeftTrigger, state.Triggers.Left, index)) buttons.Add(Buttons.LeftTrigger);
|
||||||
|
if (WasButtonJustReleased(Buttons.RightTrigger, state.Triggers.Right, index)) buttons.Add(Buttons.RightTrigger);
|
||||||
|
}
|
||||||
|
return buttons.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int PreviousGameLocations { get; private set; }
|
||||||
|
public int PreviousLocationObjects { get; private set; }
|
||||||
|
public int PreviousItems_ { get; private set; }
|
||||||
|
public Dictionary<Item, int> PreviousItems { get; private set; }
|
||||||
|
|
||||||
|
public int PreviousCombatLevel { get; private set; }
|
||||||
|
public int PreviousFarmingLevel { get; private set; }
|
||||||
|
public int PreviousFishingLevel { get; private set; }
|
||||||
|
public int PreviousForagingLevel { get; private set; }
|
||||||
|
public int PreviousMiningLevel { get; private set; }
|
||||||
|
public int PreviousLuckLevel { get; private set; }
|
||||||
|
|
||||||
|
public GameLocation PreviousGameLocation { get; private set; }
|
||||||
|
public IClickableMenu PreviousActiveMenu { get; private set; }
|
||||||
|
|
||||||
|
public Int32 PreviousTimeOfDay { get; private set; }
|
||||||
|
public Int32 PreviousDayOfMonth { get; private set; }
|
||||||
|
public String PreviousSeasonOfYear { get; private set; }
|
||||||
|
public Int32 PreviousYearOfGame { get; private set; }
|
||||||
|
|
||||||
|
public Farmer PreviousFarmer { get; private set; }
|
||||||
|
|
||||||
|
private static SGame instance;
|
||||||
|
public static SGame Instance { get { return instance; } }
|
||||||
|
|
||||||
|
public Farmer CurrentFarmer { get { return player; } }
|
||||||
|
|
||||||
|
public SGame()
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
graphics.GraphicsProfile = GraphicsProfile.HiDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
Log.Verbose("XNA Initialize");
|
||||||
|
ModItems = new Dictionary<Int32, SObject>();
|
||||||
|
PreviouslyPressedKeys = new Keys[0];
|
||||||
|
PreviouslyPressedButtons = new Buttons[4][];
|
||||||
|
for (int i = 0; i < 4; ++i) PreviouslyPressedButtons[i] = new Buttons[0];
|
||||||
|
|
||||||
|
base.Initialize();
|
||||||
|
Events.GameEvents.InvokeInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadContent()
|
||||||
|
{
|
||||||
|
Log.Verbose("XNA LoadContent");
|
||||||
|
base.LoadContent();
|
||||||
|
Events.GameEvents.InvokeLoadContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
UpdateEventCalls();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
base.Update(gameTime);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("An error occured in the base update loop: " + ex);
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.GameEvents.InvokeUpdateTick();
|
||||||
|
|
||||||
|
PreviouslyPressedKeys = CurrentlyPressedKeys;
|
||||||
|
for(PlayerIndex i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
|
||||||
|
{
|
||||||
|
PreviouslyPressedButtons[(int)i] = GetButtonsDown(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(GameTime gameTime)
|
||||||
|
{
|
||||||
|
base.Draw(gameTime);
|
||||||
|
Events.GraphicsEvents.InvokeDrawTick();
|
||||||
|
|
||||||
|
if (false)
|
||||||
|
{
|
||||||
|
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
|
||||||
|
|
||||||
|
if (CurrentLocation != null)
|
||||||
|
CurrentLocation.draw(spriteBatch);
|
||||||
|
|
||||||
|
if (player != null && player.position != null)
|
||||||
|
spriteBatch.DrawString(dialogueFont, player.position.ToString(), new Vector2(0, 180), Color.Orange);
|
||||||
|
|
||||||
|
spriteBatch.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int32 RegisterModItem(SObject modItem)
|
||||||
|
{
|
||||||
|
if (modItem.HasBeenRegistered)
|
||||||
|
{
|
||||||
|
Log.Error("The item {0} has already been registered with ID {1}", modItem.Name, modItem.RegisteredId);
|
||||||
|
return modItem.RegisteredId;
|
||||||
|
}
|
||||||
|
Int32 newId = LowestModItemID;
|
||||||
|
if (ModItems.Count > 0)
|
||||||
|
newId = Math.Max(LowestModItemID, ModItems.OrderBy(x => x.Key).First().Key + 1);
|
||||||
|
ModItems.Add(newId, modItem);
|
||||||
|
modItem.HasBeenRegistered = true;
|
||||||
|
modItem.RegisteredId = newId;
|
||||||
|
return newId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SObject PullModItemFromDict(Int32 id, bool isIndex)
|
||||||
|
{
|
||||||
|
if (isIndex)
|
||||||
|
{
|
||||||
|
if (ModItems.ElementAtOrDefault(id).Value != null)
|
||||||
|
{
|
||||||
|
return ModItems.ElementAt(id).Value.Clone();
|
||||||
|
}
|
||||||
|
Log.Error("ModItem Dictionary does not contain index: " + id.ToString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ModItems.ContainsKey(id))
|
||||||
|
{
|
||||||
|
return ModItems[id].Clone();
|
||||||
|
}
|
||||||
|
Log.Error("ModItem Dictionary does not contain ID: " + id.ToString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SGameLocation GetLocationFromName(String name)
|
||||||
|
{
|
||||||
|
return ModLocations.FirstOrDefault(n => n.name == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SGameLocation LoadOrCreateSGameLocationFromName(String name)
|
||||||
|
{
|
||||||
|
if (GetLocationFromName(name) != null)
|
||||||
|
return GetLocationFromName(name);
|
||||||
|
GameLocation gl = locations.FirstOrDefault(x => x.name == name);
|
||||||
|
if (gl != null)
|
||||||
|
{
|
||||||
|
Log.Debug("A custom location was created for the new name: " + name);
|
||||||
|
SGameLocation s = SGameLocation.ConstructFromBaseClass(gl);
|
||||||
|
ModLocations.Add(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
if (currentLocation != null && currentLocation.name == name)
|
||||||
|
{
|
||||||
|
gl = currentLocation;
|
||||||
|
Log.Debug("A custom location was created from the current location for the new name: " + name);
|
||||||
|
SGameLocation s = SGameLocation.ConstructFromBaseClass(gl);
|
||||||
|
ModLocations.Add(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Debug("A custom location could not be created for: " + name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateEventCalls()
|
||||||
|
{
|
||||||
|
KStateNow = Keyboard.GetState();
|
||||||
|
CurrentlyPressedKeys = KStateNow.GetPressedKeys();
|
||||||
|
|
||||||
|
MStateNow = Mouse.GetState();
|
||||||
|
|
||||||
|
foreach (Keys k in FramePressedKeys)
|
||||||
|
Events.ControlEvents.InvokeKeyPressed(k);
|
||||||
|
|
||||||
|
foreach (Keys k in FrameReleasedKeys)
|
||||||
|
Events.ControlEvents.InvokeKeyReleased(k);
|
||||||
|
|
||||||
|
for (PlayerIndex i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
|
||||||
|
{
|
||||||
|
Buttons[] buttons = GetFramePressedButtons(i);
|
||||||
|
foreach (Buttons b in buttons)
|
||||||
|
{
|
||||||
|
if(b == Buttons.LeftTrigger || b == Buttons.RightTrigger)
|
||||||
|
{
|
||||||
|
Events.ControlEvents.InvokeTriggerPressed(i, b, b == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Events.ControlEvents.InvokeButtonPressed(i, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PlayerIndex i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
|
||||||
|
{
|
||||||
|
foreach (Buttons b in GetFrameReleasedButtons(i))
|
||||||
|
{
|
||||||
|
if (b == Buttons.LeftTrigger || b == Buttons.RightTrigger)
|
||||||
|
{
|
||||||
|
Events.ControlEvents.InvokeTriggerReleased(i, b, b == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Events.ControlEvents.InvokeButtonReleased(i, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (KStateNow != KStatePrior)
|
||||||
|
{
|
||||||
|
Events.ControlEvents.InvokeKeyboardChanged(KStatePrior, KStateNow);
|
||||||
|
KStatePrior = KStateNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MStateNow != MStatePrior)
|
||||||
|
{
|
||||||
|
Events.ControlEvents.InvokeMouseChanged(MStatePrior, MStateNow);
|
||||||
|
MStatePrior = MStateNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeClickableMenu != null && activeClickableMenu != PreviousActiveMenu)
|
||||||
|
{
|
||||||
|
Events.MenuEvents.InvokeMenuChanged(PreviousActiveMenu, activeClickableMenu);
|
||||||
|
PreviousActiveMenu = activeClickableMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locations.GetHash() != PreviousGameLocations)
|
||||||
|
{
|
||||||
|
Events.LocationEvents.InvokeLocationsChanged(locations);
|
||||||
|
PreviousGameLocations = locations.GetHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLocation != PreviousGameLocation)
|
||||||
|
{
|
||||||
|
Events.LocationEvents.InvokeCurrentLocationChanged(PreviousGameLocation, currentLocation);
|
||||||
|
PreviousGameLocation = currentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && player != PreviousFarmer)
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeFarmerChanged(PreviousFarmer, player);
|
||||||
|
PreviousFarmer = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && player.combatLevel != PreviousCombatLevel)
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Combat, player.combatLevel);
|
||||||
|
PreviousCombatLevel = player.combatLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && player.farmingLevel != PreviousFarmingLevel)
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Farming, player.farmingLevel);
|
||||||
|
PreviousFarmingLevel = player.farmingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && player.fishingLevel != PreviousFishingLevel)
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Fishing, player.fishingLevel);
|
||||||
|
PreviousFishingLevel = player.fishingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && player.foragingLevel != PreviousForagingLevel)
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Foraging, player.foragingLevel);
|
||||||
|
PreviousForagingLevel = player.foragingLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && player.miningLevel != PreviousMiningLevel)
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Mining, player.miningLevel);
|
||||||
|
PreviousMiningLevel = player.miningLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != null && player.luckLevel != PreviousLuckLevel)
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Luck, player.luckLevel);
|
||||||
|
PreviousLuckLevel = player.luckLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStackChange> changedItems;
|
||||||
|
if (player != null && HasInventoryChanged(player.items, out changedItems))
|
||||||
|
{
|
||||||
|
Events.PlayerEvents.InvokeInventoryChanged(player.items, changedItems);
|
||||||
|
PreviousItems = player.items.Where(n => n != null).ToDictionary(n => n, n => n.Stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
var objectHash = currentLocation?.objects?.GetHash();
|
||||||
|
if(objectHash != null && PreviousLocationObjects != objectHash)
|
||||||
|
{
|
||||||
|
Events.LocationEvents.InvokeOnNewLocationObject(currentLocation.objects);
|
||||||
|
PreviousLocationObjects = objectHash ?? -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeOfDay != PreviousTimeOfDay)
|
||||||
|
{
|
||||||
|
Events.TimeEvents.InvokeTimeOfDayChanged(PreviousTimeOfDay, timeOfDay);
|
||||||
|
PreviousTimeOfDay = timeOfDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dayOfMonth != PreviousDayOfMonth)
|
||||||
|
{
|
||||||
|
Events.TimeEvents.InvokeDayOfMonthChanged(PreviousDayOfMonth, dayOfMonth);
|
||||||
|
PreviousDayOfMonth = dayOfMonth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSeason != PreviousSeasonOfYear)
|
||||||
|
{
|
||||||
|
Events.TimeEvents.InvokeSeasonOfYearChanged(PreviousSeasonOfYear, currentSeason);
|
||||||
|
PreviousSeasonOfYear = currentSeason;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year != PreviousYearOfGame)
|
||||||
|
{
|
||||||
|
Events.TimeEvents.InvokeYearOfGameChanged(PreviousYearOfGame, year);
|
||||||
|
PreviousYearOfGame = year;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasInventoryChanged(List<Item> items, out List<ItemStackChange> changedItems)
|
||||||
|
{
|
||||||
|
changedItems = new List<ItemStackChange>();
|
||||||
|
IEnumerable<Item> actualItems = items.Where(n => n != null);
|
||||||
|
foreach (var item in actualItems)
|
||||||
|
{
|
||||||
|
if (PreviousItems != null && PreviousItems.ContainsKey(item))
|
||||||
|
{
|
||||||
|
if(PreviousItems[item] != item.Stack)
|
||||||
|
{
|
||||||
|
changedItems.Add(new ItemStackChange() { Item = item, StackChange = item.Stack - PreviousItems[item], ChangeType = ChangeType.StackChange });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
changedItems.Add(new ItemStackChange() { Item = item, StackChange = item.Stack, ChangeType = ChangeType.Added });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PreviousItems != null)
|
||||||
|
{
|
||||||
|
changedItems.AddRange(PreviousItems.Where(n => !actualItems.Any(i => i == n.Key)).Select(n =>
|
||||||
|
new ItemStackChange() { Item = n.Key, StackChange = -n.Key.Stack, ChangeType = ChangeType.Removed }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (changedItems.Any());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.Eventing.Reader;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.BellsAndWhistles;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance
|
||||||
|
{
|
||||||
|
[Obsolete]
|
||||||
|
public class SGameLocation : GameLocation
|
||||||
|
{
|
||||||
|
public GameLocation BaseGameLocation { get; private set; }
|
||||||
|
|
||||||
|
public SerializableDictionary<Vector2, SObject> ModObjects { get; set; }
|
||||||
|
|
||||||
|
public static SGameLocation ConstructFromBaseClass(GameLocation baseClass, bool copyAllData = false)
|
||||||
|
{
|
||||||
|
SGameLocation s = new SGameLocation();
|
||||||
|
s.BaseGameLocation = baseClass;
|
||||||
|
s.name = baseClass.name;
|
||||||
|
|
||||||
|
Log.Debug("CONSTRUCTED: " + s.name);
|
||||||
|
|
||||||
|
if (copyAllData)
|
||||||
|
{
|
||||||
|
foreach (var v in baseClass.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fi = s.GetType().GetField(v.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
if (fi != null && !fi.IsStatic)
|
||||||
|
{
|
||||||
|
fi.SetValue(s, v.GetValue(baseClass));
|
||||||
|
//Console.WriteLine("SET {0} ON {1} TO {2}", fi.Name, s.name, v.GetValue(baseClass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SGameLocation> ConstructFromBaseClasses(List<GameLocation> baseGameLocations, bool copyAllData = false)
|
||||||
|
{
|
||||||
|
return baseGameLocations.Select(gl => ConstructFromBaseClass(gl, copyAllData)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void update(GameTime gameTime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void draw(SpriteBatch b)
|
||||||
|
{
|
||||||
|
foreach (var v in ModObjects)
|
||||||
|
{
|
||||||
|
v.Value.draw(b, (int)v.Key.X, (int)v.Key.Y, 0.999f, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SGameLocation()
|
||||||
|
{
|
||||||
|
ModObjects = new SerializableDictionary<Vector2, SObject>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,275 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Locations;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Inheritance
|
||||||
|
{
|
||||||
|
public class SObject : StardewValley.Object
|
||||||
|
{
|
||||||
|
public override String Name {
|
||||||
|
get { return name; }
|
||||||
|
set { name = value; }
|
||||||
|
}
|
||||||
|
public String Description { get; set; }
|
||||||
|
public Texture2D Texture { get; set; }
|
||||||
|
public String CategoryName { get; set; }
|
||||||
|
public Color CategoryColour { get; set; }
|
||||||
|
public Boolean IsPassable { get; set; }
|
||||||
|
public Boolean IsPlaceable { get; set; }
|
||||||
|
public Boolean HasBeenRegistered { get; set; }
|
||||||
|
public Int32 RegisteredId { get; set; }
|
||||||
|
|
||||||
|
public Int32 MaxStackSize { get; set; }
|
||||||
|
|
||||||
|
public Boolean WallMounted { get; set; }
|
||||||
|
public Vector2 DrawPosition { get; set; }
|
||||||
|
|
||||||
|
public Boolean FlaggedForPickup { get; set; }
|
||||||
|
|
||||||
|
[XmlIgnore]
|
||||||
|
public Vector2 CurrentMouse { get; protected set; }
|
||||||
|
[XmlIgnore]
|
||||||
|
public Vector2 PlacedAt { get; protected set; }
|
||||||
|
|
||||||
|
public override int Stack
|
||||||
|
{
|
||||||
|
get { return stack; }
|
||||||
|
set { stack = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public SObject()
|
||||||
|
{
|
||||||
|
name = "Modded Item Name";
|
||||||
|
Description = "Modded Item Description";
|
||||||
|
CategoryName = "Modded Item Category";
|
||||||
|
Category = 4163;
|
||||||
|
CategoryColour = Color.White;
|
||||||
|
IsPassable = false;
|
||||||
|
IsPlaceable = false;
|
||||||
|
boundingBox = new Rectangle(0, 0, 64, 64);
|
||||||
|
MaxStackSize = 999;
|
||||||
|
|
||||||
|
type = "interactive";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string getDescription()
|
||||||
|
{
|
||||||
|
return Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void draw(SpriteBatch spriteBatch, int x, int y, float alpha = 1)
|
||||||
|
{
|
||||||
|
if (Texture != null)
|
||||||
|
{
|
||||||
|
spriteBatch.Draw(Texture, Game1.GlobalToLocal(Game1.viewport, new Vector2((float)(((x * Game1.tileSize) + (Game1.tileSize / 2)) + ((this.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0)), (float)(((y * Game1.tileSize) + (Game1.tileSize / 2)) + ((this.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0)))), new Rectangle?(Game1.currentLocation.getSourceRectForObject(this.ParentSheetIndex)), (Color)(Color.White * alpha), 0f, new Vector2(8f, 8f), (this.scale.Y > 1f) ? this.getScale().Y : ((float)Game1.pixelZoom), this.flipped ? SpriteEffects.FlipHorizontally : SpriteEffects.None, (this.isPassable() ? ((float)this.getBoundingBox(new Vector2((float)x, (float)y)).Top) : ((float)this.getBoundingBox(new Vector2((float)x, (float)y)).Bottom)) / 10000f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawAsProp(SpriteBatch b)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void draw(SpriteBatch spriteBatch, int xNonTile, int yNonTile, float layerDepth, float alpha = 1)
|
||||||
|
{
|
||||||
|
Log.Debug("THIS DRAW FUNCTION IS NOT IMPLEMENTED I WANT TO KNOW WHERE IT IS CALLED");
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Texture != null)
|
||||||
|
{
|
||||||
|
int targSize = Game1.tileSize;
|
||||||
|
int midX = (int) ((xNonTile) + 32);
|
||||||
|
int midY = (int) ((yNonTile) + 32);
|
||||||
|
|
||||||
|
int targX = midX - targSize / 2;
|
||||||
|
int targY = midY - targSize / 2;
|
||||||
|
|
||||||
|
Rectangle targ = new Rectangle(targX, targY, targSize, targSize);
|
||||||
|
spriteBatch.Draw(Texture, targ, null, new Color(255, 255, 255, 255f * alpha), 0, Vector2.Zero, SpriteEffects.None, layerDepth);
|
||||||
|
//spriteBatch.Draw(Program.DebugPixel, targ, null, Color.Red, 0, Vector2.Zero, SpriteEffects.None, layerDepth);
|
||||||
|
/*
|
||||||
|
spriteBatch.DrawString(Game1.dialogueFont, "TARG: " + targ, new Vector2(128, 0), Color.Red);
|
||||||
|
spriteBatch.DrawString(Game1.dialogueFont, ".", new Vector2(targX * 0.5f, targY), Color.Orange);
|
||||||
|
spriteBatch.DrawString(Game1.dialogueFont, ".", new Vector2(targX, targY), Color.Red);
|
||||||
|
spriteBatch.DrawString(Game1.dialogueFont, ".", new Vector2(targX * 1.5f, targY), Color.Yellow);
|
||||||
|
spriteBatch.DrawString(Game1.dialogueFont, ".", new Vector2(targX * 2f, targY), Color.Green);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex.ToString());
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void drawInMenu(SpriteBatch spriteBatch, Vector2 location, float scaleSize, float transparency, float layerDepth, bool drawStackNumber)
|
||||||
|
{
|
||||||
|
if (this.isRecipe)
|
||||||
|
{
|
||||||
|
transparency = 0.5f;
|
||||||
|
scaleSize *= 0.75f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Texture != null)
|
||||||
|
{
|
||||||
|
int targSize = (int) (64 * scaleSize * 0.9f);
|
||||||
|
int midX = (int) ((location.X) + 32);
|
||||||
|
int midY = (int) ((location.Y) + 32);
|
||||||
|
|
||||||
|
int targX = midX - targSize / 2;
|
||||||
|
int targY = midY - targSize / 2;
|
||||||
|
|
||||||
|
spriteBatch.Draw(Texture, new Rectangle(targX, targY, targSize, targSize), null, new Color(255, 255, 255, transparency), 0, Vector2.Zero, SpriteEffects.None, layerDepth);
|
||||||
|
}
|
||||||
|
if (drawStackNumber)
|
||||||
|
{
|
||||||
|
float scale = 0.5f + scaleSize;
|
||||||
|
Game1.drawWithBorder(string.Concat(this.stack.ToString()), Color.Black, Color.White, location + new Vector2((float) Game1.tileSize - Game1.tinyFont.MeasureString(string.Concat(this.stack.ToString())).X * scale, (float) Game1.tileSize - (float) ((double) Game1.tinyFont.MeasureString(string.Concat(this.stack.ToString())).Y * 3.0f / 4.0f) * scale), 0.0f, scale, 1f, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void drawWhenHeld(SpriteBatch spriteBatch, Vector2 objectPosition, Farmer f)
|
||||||
|
{
|
||||||
|
if (Texture != null)
|
||||||
|
{
|
||||||
|
int targSize = 64;
|
||||||
|
int midX = (int) ((objectPosition.X) + 32);
|
||||||
|
int midY = (int) ((objectPosition.Y) + 32);
|
||||||
|
|
||||||
|
int targX = midX - targSize / 2;
|
||||||
|
int targY = midY - targSize / 2;
|
||||||
|
|
||||||
|
spriteBatch.Draw(Texture, new Rectangle(targX, targY, targSize, targSize), null, Color.White, 0, Vector2.Zero, SpriteEffects.None, (f.getStandingY() + 2) / 10000f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Color getCategoryColor()
|
||||||
|
{
|
||||||
|
return CategoryColour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string getCategoryName()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(CategoryName))
|
||||||
|
return "Modded Item";
|
||||||
|
return CategoryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool isPassable()
|
||||||
|
{
|
||||||
|
return IsPassable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool isPlaceable()
|
||||||
|
{
|
||||||
|
return IsPlaceable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int maximumStackSize()
|
||||||
|
{
|
||||||
|
return MaxStackSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SObject Clone()
|
||||||
|
{
|
||||||
|
SObject toRet = new SObject();
|
||||||
|
|
||||||
|
toRet.Name = this.Name;
|
||||||
|
toRet.CategoryName = this.CategoryName;
|
||||||
|
toRet.Description = this.Description;
|
||||||
|
toRet.Texture = this.Texture;
|
||||||
|
toRet.IsPassable = this.IsPassable;
|
||||||
|
toRet.IsPlaceable = this.IsPlaceable;
|
||||||
|
toRet.quality = this.quality;
|
||||||
|
toRet.scale = this.scale;
|
||||||
|
toRet.isSpawnedObject = this.isSpawnedObject;
|
||||||
|
toRet.isRecipe = this.isRecipe;
|
||||||
|
toRet.questItem = this.questItem;
|
||||||
|
toRet.stack = 1;
|
||||||
|
toRet.HasBeenRegistered = this.HasBeenRegistered;
|
||||||
|
toRet.RegisteredId = this.RegisteredId;
|
||||||
|
|
||||||
|
return toRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Item getOne()
|
||||||
|
{
|
||||||
|
return this.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void actionWhenBeingHeld(Farmer who)
|
||||||
|
{
|
||||||
|
int x = Game1.oldMouseState.X + Game1.viewport.X;
|
||||||
|
int y = Game1.oldMouseState.Y + Game1.viewport.Y;
|
||||||
|
|
||||||
|
x = x / Game1.tileSize;
|
||||||
|
y = y / Game1.tileSize;
|
||||||
|
|
||||||
|
CurrentMouse = new Vector2(x, y);
|
||||||
|
//Program.LogDebug(canBePlacedHere(Game1.currentLocation, CurrentMouse));
|
||||||
|
base.actionWhenBeingHeld(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool canBePlacedHere(GameLocation l, Vector2 tile)
|
||||||
|
{
|
||||||
|
//Program.LogDebug(CurrentMouse.ToString().Replace("{", "").Replace("}", ""));
|
||||||
|
if (!l.objects.ContainsKey(tile))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool placementAction(GameLocation location, int x, int y, Farmer who = null)
|
||||||
|
{
|
||||||
|
if (Game1.didPlayerJustRightClick())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
x = (x / Game1.tileSize);
|
||||||
|
y = (y / Game1.tileSize);
|
||||||
|
|
||||||
|
//Program.LogDebug(x + " - " + y);
|
||||||
|
//Console.ReadKey();
|
||||||
|
|
||||||
|
Vector2 key = new Vector2(x, y);
|
||||||
|
|
||||||
|
if (!canBePlacedHere(location, key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SObject s = Clone();
|
||||||
|
|
||||||
|
s.PlacedAt = key;
|
||||||
|
s.boundingBox = new Rectangle(x / Game1.tileSize * Game1.tileSize, y / Game1.tileSize * Game1.tileSize, this.boundingBox.Width, this.boundingBox.Height);
|
||||||
|
|
||||||
|
location.objects.Add(key, s);
|
||||||
|
Log.Verbose("{0} - {1}", this.GetHashCode(), s.GetHashCode());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void actionOnPlayerEntry()
|
||||||
|
{
|
||||||
|
//base.actionOnPlayerEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void drawPlacementBounds(SpriteBatch spriteBatch, GameLocation location)
|
||||||
|
{
|
||||||
|
if (canBePlacedHere(location, CurrentMouse))
|
||||||
|
{
|
||||||
|
int targSize = Game1.tileSize;
|
||||||
|
|
||||||
|
int x = Game1.oldMouseState.X + Game1.viewport.X;
|
||||||
|
int y = Game1.oldMouseState.Y + Game1.viewport.Y;
|
||||||
|
spriteBatch.Draw(Game1.mouseCursors, new Vector2((float)(x / Game1.tileSize * Game1.tileSize - Game1.viewport.X), (float)(y / Game1.tileSize * Game1.tileSize - Game1.viewport.Y)), new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(Utility.playerCanPlaceItemHere(location, (Item)this, x, y, Game1.player) ? 194 : 210, 388, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)Game1.pixelZoom, SpriteEffects.None, 0.01f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,182 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class to organize logging calls.
|
||||||
|
/// </summary>
|
||||||
|
public class Log
|
||||||
|
{
|
||||||
|
private static StreamWriter _logStream;
|
||||||
|
private static string _logPath;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set up the logging stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logPath"></param>
|
||||||
|
public static void Initialize(string logPath)
|
||||||
|
{
|
||||||
|
_logPath = logPath;
|
||||||
|
var logFile = string.Format("{0}\\MODDED_ProgramLog.Log_LATEST.txt", logPath);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logStream = new StreamWriter(logFile, false);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// TODO: not use general exception
|
||||||
|
Log.Error("Could not initialize LogStream - Logging is disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Print provided parameters to the console/file as applicable
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Desired message</param>
|
||||||
|
/// <param name="suppressMessage">When true, writes to ONLY console and not the log file.</param>
|
||||||
|
/// <param name="values">Additional params to be added to the message</param>
|
||||||
|
private static void PrintLog(object message, bool disableLogging, params object[] values)
|
||||||
|
{
|
||||||
|
string logOutput = string.Format("[{0}] {1}", System.DateTime.Now.ToLongTimeString(), String.Format(message.ToString(), values));
|
||||||
|
Console.WriteLine(logOutput);
|
||||||
|
|
||||||
|
if (_logStream != null && !disableLogging)
|
||||||
|
{
|
||||||
|
_logStream.WriteLine(logOutput);
|
||||||
|
_logStream.Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Successful message to display to console and logging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Success(object message, params object[] values)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Log.PrintLog(message?.ToString(), false, values);
|
||||||
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generic comment to display to console and logging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Verbose(object message, params object[] values)
|
||||||
|
{
|
||||||
|
Log.PrintLog(message?.ToString(), false, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Additional comment to display to console and logging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Comment(object message, params object[] values)
|
||||||
|
{
|
||||||
|
Log.PrintLog(message?.ToString(), false, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Additional comment to display to console and logging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Warning(object message, params object[] values)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Log.PrintLog(message?.ToString(), false, values);
|
||||||
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message for only console. Does not appear in logging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Info(object message, params object[] values)
|
||||||
|
{
|
||||||
|
Log.PrintLog(message.ToString(), true, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Important message indicating an error.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Error(object message, params object[] values)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Log.PrintLog(message.ToString(), false, values);
|
||||||
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A message displayed only while in DEBUG mode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="values"></param>
|
||||||
|
public static void Debug(object message, params object[] values)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Log.PrintLog(message.ToString(), false, values);
|
||||||
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Catch unhandled exception from the application
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Should be moved out of here if we do more than just log the exception.</remarks>
|
||||||
|
public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("An exception has been caught");
|
||||||
|
File.WriteAllText(_logPath + "\\MODDED_ErrorLog.Log_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.ExceptionObject.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Catch thread exception from the application
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Should be moved out of here if we do more than just log the exception.</remarks>
|
||||||
|
public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("A thread exception has been caught");
|
||||||
|
File.WriteAllText(_logPath + "\\MODDED_ErrorLog.Log_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.Exception.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// I'm including the following for now because they have a lot of references with different uses.
|
||||||
|
// They should be removed since they do not provide any insight into actual problems, and other log methods should be used.
|
||||||
|
|
||||||
|
public static void LogValueNotSpecified()
|
||||||
|
{
|
||||||
|
Error("<value> must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogObjectValueNotSpecified()
|
||||||
|
{
|
||||||
|
Error("<object> and <value> must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogValueInvalid()
|
||||||
|
{
|
||||||
|
Error("<value> is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogObjectInvalid()
|
||||||
|
{
|
||||||
|
Error("<object> is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogValueNotInt32()
|
||||||
|
{
|
||||||
|
Error("<value> must be a whole number (Int32)");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
public class Mod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of your mod.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string Name { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the mod's authour.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string Authour { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The version of the mod.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string Version { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A description of the mod.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string Description { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A basic method that is the entry-point of your mod. It will always be called once when the mod loads.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Entry(params object[] objects)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using StardewValley;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
class ModItem : StardewValley.Object
|
||||||
|
{
|
||||||
|
public Item AsItem { get { return (Item) this; } }
|
||||||
|
public override string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public int ID { get; set; }
|
||||||
|
public Texture2D Texture { get; set; }
|
||||||
|
|
||||||
|
public ModItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,373 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using StardewModdingAPI.Events;
|
||||||
|
using StardewModdingAPI.ExtensionMethods;
|
||||||
|
using StardewModdingAPI.Helpers;
|
||||||
|
using StardewModdingAPI.Inheritance;
|
||||||
|
using StardewModdingAPI.Inheritance.Menus;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
private static List<string> _modPaths;
|
||||||
|
private static List<string> _modContentPaths;
|
||||||
|
|
||||||
|
public static Texture2D DebugPixel { get; private set; }
|
||||||
|
|
||||||
|
public static bool IsGameReferenceDirty { get; set; }
|
||||||
|
|
||||||
|
public static object gameInst;
|
||||||
|
|
||||||
|
public static Game1 _gamePtr;
|
||||||
|
public static Game1 gamePtr
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(IsGameReferenceDirty && gameInst != null)
|
||||||
|
{
|
||||||
|
_gamePtr = gameInst.Copy<Game1>();
|
||||||
|
}
|
||||||
|
return _gamePtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ready;
|
||||||
|
|
||||||
|
public static Form StardewForm;
|
||||||
|
|
||||||
|
public static Thread gameThread;
|
||||||
|
public static Thread consoleInputThread;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main method holding the API execution
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConfigureUI();
|
||||||
|
ConfigurePaths();
|
||||||
|
ConfigureMethodInjection();
|
||||||
|
ConfigureSDV();
|
||||||
|
GameRunInvoker();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Catch and display all exceptions.
|
||||||
|
StardewModdingAPI.Log.Error("Critical error: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
StardewModdingAPI.Log.Comment("The API will now terminate. Press any key to continue...");
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures Mono.Cecil injections
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureMethodInjection()
|
||||||
|
{
|
||||||
|
StardewAssembly.ModifyStardewAssembly();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
StardewAssembly.WriteModifiedExe();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void Test(object instance)
|
||||||
|
{
|
||||||
|
gameInst = instance;
|
||||||
|
IsGameReferenceDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set up the console properties
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureUI()
|
||||||
|
{
|
||||||
|
Console.Title = Constants.ConsoleTitle;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Console.Title += " - DEBUG IS NOT FALSE, AUTHOUR NEEDS TO REUPLOAD THIS VERSION";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setup the required paths and logging
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigurePaths()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Info("Validating api paths...");
|
||||||
|
|
||||||
|
_modPaths = new List<string>();
|
||||||
|
_modContentPaths = new List<string>();
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: Have an app.config and put the paths inside it so users can define locations to load mods from
|
||||||
|
_modPaths.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "Mods"));
|
||||||
|
_modPaths.Add(Path.Combine(Constants.ExecutionPath, "Mods"));
|
||||||
|
_modContentPaths.Add(Path.Combine(Constants.ExecutionPath, "Mods", "Content"));
|
||||||
|
_modContentPaths.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "Mods", "Content"));
|
||||||
|
|
||||||
|
//Checks that all defined modpaths exist as directories
|
||||||
|
_modPaths.ForEach(path => VerifyPath(path));
|
||||||
|
_modContentPaths.ForEach(path => VerifyPath(path));
|
||||||
|
VerifyPath(Constants.LogPath);
|
||||||
|
|
||||||
|
StardewModdingAPI.Log.Initialize(Constants.LogPath);
|
||||||
|
|
||||||
|
if (!File.Exists(Constants.ExecutionPath + "\\Stardew Valley.exe"))
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("Replace this");
|
||||||
|
//throw new FileNotFoundException(string.Format("Could not found: {0}\\Stardew Valley.exe", Constants.ExecutionPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load Stardev Valley and control features
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureSDV()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Info("Initializing SDV Assembly...");
|
||||||
|
|
||||||
|
// Load in the assembly - ignores security
|
||||||
|
StardewAssembly.LoadStardewAssembly();
|
||||||
|
StardewModdingAPI.Log.Comment("SDV Loaded Into Memory");
|
||||||
|
|
||||||
|
// Change the game's version
|
||||||
|
StardewModdingAPI.Log.Verbose("Injecting New SDV Version...");
|
||||||
|
Game1.version += string.Format("-Z_MODDED | SMAPI {0}", Constants.VersionString);
|
||||||
|
|
||||||
|
// Create the thread for the game to run in.
|
||||||
|
Application.ThreadException += StardewModdingAPI.Log.Application_ThreadException;
|
||||||
|
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||||
|
AppDomain.CurrentDomain.UnhandledException += StardewModdingAPI.Log.CurrentDomain_UnhandledException;
|
||||||
|
|
||||||
|
|
||||||
|
//Create definition to listen for input
|
||||||
|
StardewModdingAPI.Log.Verbose("Initializing Console Input Thread...");
|
||||||
|
consoleInputThread = new Thread(ConsoleInputThread);
|
||||||
|
|
||||||
|
Command.RegisterCommand("help", "Lists all commands | 'help <cmd>' returns command description").CommandFired += help_CommandFired;
|
||||||
|
|
||||||
|
StardewAssembly.Launch();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wrap the 'RunGame' method for console output
|
||||||
|
/// </summary>
|
||||||
|
private static void GameRunInvoker()
|
||||||
|
{
|
||||||
|
//Game's in memory now, send the event
|
||||||
|
StardewModdingAPI.Log.Verbose("Game Loaded");
|
||||||
|
Events.GameEvents.InvokeGameLoaded();
|
||||||
|
|
||||||
|
StardewModdingAPI.Log.Comment("Type 'help' for help, or 'help <cmd>' for a command's usage");
|
||||||
|
//Begin listening to input
|
||||||
|
consoleInputThread.Start();
|
||||||
|
|
||||||
|
|
||||||
|
while (ready)
|
||||||
|
{
|
||||||
|
//Check if the game is still running 10 times a second
|
||||||
|
Thread.Sleep(1000 / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//abort the thread, we're closing
|
||||||
|
if (consoleInputThread != null && consoleInputThread.ThreadState == ThreadState.Running)
|
||||||
|
consoleInputThread.Abort();
|
||||||
|
|
||||||
|
StardewModdingAPI.Log.Verbose("Game Execution Finished");
|
||||||
|
StardewModdingAPI.Log.Verbose("Shutting Down...");
|
||||||
|
Thread.Sleep(100);
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create the given directory path if it does not exist
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">Desired directory path</param>
|
||||||
|
private static void VerifyPath(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(path))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("Could not create a path: " + path + "\n\n" + ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
static void StardewForm_Closing(object sender, CancelEventArgs e)
|
||||||
|
{
|
||||||
|
e.Cancel = true;
|
||||||
|
|
||||||
|
if (true || MessageBox.Show("Are you sure you would like to quit Stardew Valley?\nUnsaved progress will be lost!", "Confirm Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
|
||||||
|
{
|
||||||
|
gamePtr.Exit();
|
||||||
|
gamePtr.Dispose();
|
||||||
|
StardewForm.Hide();
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LoadMods()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Verbose("LOADING MODS");
|
||||||
|
int loadedMods = 0;
|
||||||
|
foreach (string ModPath in _modPaths)
|
||||||
|
{
|
||||||
|
foreach (String s in Directory.GetFiles(ModPath, "*.dll"))
|
||||||
|
{
|
||||||
|
if (s.Contains("StardewInjector"))
|
||||||
|
continue;
|
||||||
|
StardewModdingAPI.Log.Success("Found DLL: " + s);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Assembly mod = Assembly.UnsafeLoadFrom(s); //to combat internet-downloaded DLLs
|
||||||
|
|
||||||
|
if (mod.DefinedTypes.Count(x => x.BaseType == typeof(Mod)) > 0)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Verbose("Loading Mod DLL...");
|
||||||
|
TypeInfo tar = mod.DefinedTypes.First(x => x.BaseType == typeof(Mod));
|
||||||
|
Mod m = (Mod)mod.CreateInstance(tar.ToString());
|
||||||
|
Console.WriteLine("LOADED MOD: {0} by {1} - Version {2} | Description: {3}", m.Name, m.Authour, m.Version, m.Description);
|
||||||
|
loadedMods += 1;
|
||||||
|
m.Entry();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("Invalid Mod DLL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("Failed to load mod '{0}'. Exception details:\n" + ex, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StardewModdingAPI.Log.Success("LOADED {0} MODS", loadedMods);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ConsoleInputThread()
|
||||||
|
{
|
||||||
|
string input = string.Empty;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Command.CallCommand(Console.ReadLine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void StardewInvoke(Action a)
|
||||||
|
{
|
||||||
|
StardewForm.Invoke(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void help_CommandFired(object o, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
Command fnd = Command.FindCommand(e.Command.CalledArgs[0]);
|
||||||
|
if (fnd == null)
|
||||||
|
StardewModdingAPI.Log.Error("The command specified could not be found");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fnd.CommandArgs.Length > 0)
|
||||||
|
StardewModdingAPI.Log.Info("{0}: {1} - {2}", fnd.CommandName, fnd.CommandDesc, fnd.CommandArgs.ToSingular());
|
||||||
|
else
|
||||||
|
StardewModdingAPI.Log.Info("{0}: {1}", fnd.CommandName, fnd.CommandDesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
StardewModdingAPI.Log.Info("Commands: " + Command.RegisteredCommands.Select(x => x.CommandName).ToSingular());
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Logging
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void Log(object o, params object[] format)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Info(o, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogColour(ConsoleColor c, object o, params object[] format)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Info(o, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogInfo(object o, params object[] format)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Info(o, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogError(object o, params object[] format)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error(o, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogDebug(object o, params object[] format)
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Debug(o, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogValueNotSpecified()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("<value> must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogObjectValueNotSpecified()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("<object> and <value> must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogValueInvalid()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("<value> is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogObjectInvalid()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("<object> is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("This method is obsolete and will be removed in v0.39, please use the appropriate methods in the Log class")]
|
||||||
|
public static void LogValueNotInt32()
|
||||||
|
{
|
||||||
|
StardewModdingAPI.Log.Error("<value> must be a whole number (Int32)");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,27 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
// associated with an assembly.
|
// associated with an assembly.
|
||||||
[assembly: AssemblyTitle("Loader")]
|
[assembly: AssemblyTitle("StardewModdingAPI")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("Loader")]
|
[assembly: AssemblyProduct("StardewModdingAPI")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("5c3f7f42-fefd-43db-aaea-92ea3bcad531")]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
// Version information for an assembly consists of the following four values:
|
||||||
//
|
//
|
||||||
// Major Version
|
// Major Version
|
|
@ -0,0 +1,198 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{F1A573B0-F436-472C-AE29-0B91EA6B9F8F}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>StardewModdingAPI</RootNamespace>
|
||||||
|
<AssemblyName>StardewModdingAPI</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<SccProjectName>
|
||||||
|
</SccProjectName>
|
||||||
|
<SccLocalPath>
|
||||||
|
</SccLocalPath>
|
||||||
|
<SccAuxPath>
|
||||||
|
</SccAuxPath>
|
||||||
|
<SccProvider>
|
||||||
|
</SccProvider>
|
||||||
|
<PublishUrl>publish\</PublishUrl>
|
||||||
|
<Install>true</Install>
|
||||||
|
<InstallFrom>Disk</InstallFrom>
|
||||||
|
<UpdateEnabled>false</UpdateEnabled>
|
||||||
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||||
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
|
<UpdateRequired>false</UpdateRequired>
|
||||||
|
<MapFileExtensions>true</MapFileExtensions>
|
||||||
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
|
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||||
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(SteamInstallPath)' != ''">
|
||||||
|
<PropertyGroup>
|
||||||
|
<SteamPath>$(SteamInstallPath)</SteamPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SteamPath>..\..\..\..\Games\SteamLibrary</SteamPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<DefineConstants>DEBUG</DefineConstants>
|
||||||
|
<UseVSHostingProcess>true</UseVSHostingProcess>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<OutputPath>bin\x86\Release\</OutputPath>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
|
||||||
|
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Stardew Valley, Version=1.0.5912.41135, Culture=neutral, processorArchitecture=x86">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="xTile">
|
||||||
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\xTile.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="API\Game.cs" />
|
||||||
|
<Compile Include="Command.cs" />
|
||||||
|
<Compile Include="Constants.cs" />
|
||||||
|
<Compile Include="Entities\SCharacter.cs" />
|
||||||
|
<Compile Include="Entities\SFarm.cs" />
|
||||||
|
<Compile Include="Entities\SFarmAnimal.cs" />
|
||||||
|
<Compile Include="Entities\SNpc.cs" />
|
||||||
|
<Compile Include="Entities\SPlayer.cs" />
|
||||||
|
<Compile Include="Events\Controls.cs" />
|
||||||
|
<Compile Include="Events\EventArgs.cs" />
|
||||||
|
<Compile Include="Events\FarmAnimal.cs" />
|
||||||
|
<Compile Include="Events\Game.cs" />
|
||||||
|
<Compile Include="Events\Graphics.cs" />
|
||||||
|
<Compile Include="Events\Location.cs" />
|
||||||
|
<Compile Include="Events\Menu.cs" />
|
||||||
|
<Compile Include="Events\Mine.cs" />
|
||||||
|
<Compile Include="Events\Player.cs" />
|
||||||
|
<Compile Include="Events\Time.cs" />
|
||||||
|
<Compile Include="ExtensionMethods\Array.cs" />
|
||||||
|
<Compile Include="ExtensionMethods\Object.cs" />
|
||||||
|
<Compile Include="Extensions.cs" />
|
||||||
|
<Compile Include="Helpers\CecilContext.cs" />
|
||||||
|
<Compile Include="Helpers\CecilHelper.cs" />
|
||||||
|
<Compile Include="Helpers\ReflectionHelper.cs" />
|
||||||
|
<Compile Include="Helpers\StardewAssembly.cs" />
|
||||||
|
<Compile Include="Inheritance\ItemStackChange.cs" />
|
||||||
|
<Compile Include="Inheritance\Menus\SBobberBar.cs" />
|
||||||
|
<Compile Include="Inheritance\Menus\SGameMenu.cs" />
|
||||||
|
<Compile Include="Inheritance\Menus\SInventoryPage.cs" />
|
||||||
|
<Compile Include="Inheritance\Minigames\SMinigameBase.cs" />
|
||||||
|
<Compile Include="Inheritance\SGameLocation.cs" />
|
||||||
|
<Compile Include="Inheritance\SObject.cs" />
|
||||||
|
<Compile Include="Log.cs" />
|
||||||
|
<Compile Include="Mod.cs" />
|
||||||
|
<Compile Include="ModItem.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Inheritance\SGame.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="icon.ico" />
|
||||||
|
<Content Include="steam_appid.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
|
<Install>false</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<PostBuildEvent>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</PropertyGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Mono.Cecil" version="0.9.6.1" targetFramework="net45" />
|
||||||
|
</packages>
|
|
@ -1,21 +1,27 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Android.App;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
// associated with an assembly.
|
// associated with an assembly.
|
||||||
[assembly: AssemblyTitle("MobilePatch")]
|
[assembly: AssemblyTitle("TrainerMod")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("MobilePatch")]
|
[assembly: AssemblyProduct("TrainerMod")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2023")]
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("76791e28-b1b5-407c-82d6-50c3e5b7e037")]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
// Version information for an assembly consists of the following four values:
|
||||||
//
|
//
|
||||||
// Major Version
|
// Major Version
|
|
@ -0,0 +1,771 @@
|
||||||
|
using StardewModdingAPI;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Mime;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using StardewModdingAPI.Inheritance;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Tools;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using StardewValley.Objects;
|
||||||
|
using StardewModdingAPI.Events;
|
||||||
|
|
||||||
|
namespace TrainerMod
|
||||||
|
{
|
||||||
|
public class TrainerMod : Mod
|
||||||
|
{
|
||||||
|
public override string Name
|
||||||
|
{
|
||||||
|
get { return "Trainer Mod"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Authour
|
||||||
|
{
|
||||||
|
get { return "Zoryn Aaron"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Version
|
||||||
|
{
|
||||||
|
get { return "1.0"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Description
|
||||||
|
{
|
||||||
|
get { return "Registers several commands to use. Most commands are trainer-like in that they offer forms of cheating."; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int frozenTime;
|
||||||
|
public static bool infHealth, infStamina, infMoney, freezeTime;
|
||||||
|
|
||||||
|
public override void Entry(params object[] objects)
|
||||||
|
{
|
||||||
|
RegisterCommands();
|
||||||
|
GameEvents.UpdateTick += Events_UpdateTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Events_UpdateTick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (Game1.player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (infHealth)
|
||||||
|
{
|
||||||
|
Game1.player.health = Game1.player.maxHealth;
|
||||||
|
}
|
||||||
|
if (infStamina)
|
||||||
|
{
|
||||||
|
Game1.player.stamina = Game1.player.MaxStamina;
|
||||||
|
}
|
||||||
|
if (infMoney)
|
||||||
|
{
|
||||||
|
Game1.player.money = 999999;
|
||||||
|
}
|
||||||
|
if (freezeTime)
|
||||||
|
{
|
||||||
|
Game1.timeOfDay = frozenTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterCommands()
|
||||||
|
{
|
||||||
|
Command.RegisterCommand("types", "Lists all value types | types").CommandFired += types_CommandFired;
|
||||||
|
|
||||||
|
Command.RegisterCommand("hide", "Hides the game form | hide").CommandFired += hide_CommandFired;
|
||||||
|
Command.RegisterCommand("show", "Shows the game form | show").CommandFired += show_CommandFired;
|
||||||
|
|
||||||
|
Command.RegisterCommand("save", "Saves the game? Doesn't seem to work. | save").CommandFired += save_CommandFired;
|
||||||
|
Command.RegisterCommand("load", "Shows the load screen | load").CommandFired += load_CommandFired;
|
||||||
|
|
||||||
|
Command.RegisterCommand("exit", "Closes the game | exit").CommandFired += exit_CommandFired;
|
||||||
|
Command.RegisterCommand("stop", "Closes the game | stop").CommandFired += exit_CommandFired;
|
||||||
|
|
||||||
|
Command.RegisterCommand("player_setname", "Sets the player's name | player_setname <object> <value>", new[] { "(player, pet, farm)<object> (String)<value> The target name" }).CommandFired += player_setName;
|
||||||
|
Command.RegisterCommand("player_setmoney", "Sets the player's money | player_setmoney <value>|inf", new[] { "(Int32)<value> The target money" }).CommandFired += player_setMoney;
|
||||||
|
Command.RegisterCommand("player_setstamina", "Sets the player's stamina | player_setstamina <value>|inf", new[] { "(Int32)<value> The target stamina" }).CommandFired += player_setStamina;
|
||||||
|
Command.RegisterCommand("player_setmaxstamina", "Sets the player's max stamina | player_setmaxstamina <value>", new[] { "(Int32)<value> The target max stamina" }).CommandFired += player_setMaxStamina;
|
||||||
|
Command.RegisterCommand("player_sethealth", "Sets the player's health | player_sethealth <value>|inf", new[] { "(Int32)<value> The target health" }).CommandFired += player_setHealth;
|
||||||
|
Command.RegisterCommand("player_setmaxhealth", "Sets the player's max health | player_setmaxhealth <value>", new[] { "(Int32)<value> The target max health" }).CommandFired += player_setMaxHealth;
|
||||||
|
Command.RegisterCommand("player_setimmunity", "Sets the player's immunity | player_setimmunity <value>", new[] { "(Int32)<value> The target immunity" }).CommandFired += player_setImmunity;
|
||||||
|
|
||||||
|
Command.RegisterCommand("player_setlevel", "Sets the player's specified skill to the specified value | player_setlevel <skill> <value>", new[] { "(luck, mining, combat, farming, fishing, foraging)<skill> (1-10)<value> The target level" }).CommandFired += player_setLevel;
|
||||||
|
Command.RegisterCommand("player_setspeed", "Sets the player's speed to the specified value?", new[] { "(Int32)<value> The target speed [0 is normal]" }).CommandFired += player_setSpeed;
|
||||||
|
Command.RegisterCommand("player_changecolour", "Sets the player's colour of the specified object | player_changecolor <object> <colour>", new[] { "(hair, eyes, pants)<object> (r,g,b)<colour>" }).CommandFired += player_changeColour;
|
||||||
|
Command.RegisterCommand("player_changestyle", "Sets the player's style of the specified object | player_changecolor <object> <value>", new[] { "(hair, shirt, skin, acc, shoe, swim, gender)<object> (Int32)<value>" }).CommandFired += player_changeStyle;
|
||||||
|
|
||||||
|
Command.RegisterCommand("player_additem", "Gives the player an item | player_additem <item> [count] [quality]", new[] { "(Int32)<id> (Int32)[count] (Int32)[quality]" }).CommandFired += player_addItem;
|
||||||
|
Command.RegisterCommand("player_addmelee", "Gives the player a melee item | player_addmelee <item>", new[] { "?<item>" }).CommandFired += player_addMelee;
|
||||||
|
Command.RegisterCommand("player_addring", "Gives the player a ring | player_addring <item>", new[] { "?<item>" }).CommandFired += player_addRing;
|
||||||
|
|
||||||
|
Command.RegisterCommand("out_items", "Outputs a list of items | out_items", new[] { "" }).CommandFired += out_items;
|
||||||
|
Command.RegisterCommand("out_melee", "Outputs a list of melee weapons | out_melee", new[] { "" }).CommandFired += out_melee;
|
||||||
|
Command.RegisterCommand("out_rings", "Outputs a list of rings | out_rings", new[] { "" }).CommandFired += out_rings;
|
||||||
|
Command.RegisterCommand("newitem", "Outputs a list of melee weapons | out_melee", new[] { "" }).CommandFired += RegisterNewItem;
|
||||||
|
|
||||||
|
Command.RegisterCommand("world_settime", "Sets the time to the specified value | world_settime <value>", new[] { "(Int32)<value> The target time [06:00 AM is 600]" }).CommandFired += world_setTime;
|
||||||
|
Command.RegisterCommand("world_freezetime", "Freezes or thaws time | world_freezetime <value>", new[] { "(0 - 1)<value> Whether or not to freeze time. 0 is thawed, 1 is frozen" }).CommandFired += world_freezeTime;
|
||||||
|
Command.RegisterCommand("world_setday", "Sets the day to the specified value | world_setday <value>", new[] { "(Int32)<value> The target day [1-28]" }).CommandFired += world_setDay;
|
||||||
|
Command.RegisterCommand("world_setseason", "Sets the season to the specified value | world_setseason <value>", new[] { "(winter, spring, summer, fall)<value> The target season" }).CommandFired += world_setSeason;
|
||||||
|
Command.RegisterCommand("world_downminelevel", "Goes down one mine level? | world_downminelevel", new[] { "" }).CommandFired += world_downMineLevel;
|
||||||
|
Command.RegisterCommand("world_setminelevel", "Sets mine level? | world_setminelevel", new[] { "(Int32)<value> The target level" }).CommandFired += world_setMineLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void types_CommandFired(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
Log.Verbose("[Int32: {0} - {1}], [Int64: {2} - {3}], [String: \"raw text\"], [Colour: r,g,b (EG: 128, 32, 255)]", Int32.MinValue, Int32.MaxValue, Int64.MinValue, Int64.MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hide_CommandFired(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
Program.StardewInvoke(() => { Program.StardewForm.Hide(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_CommandFired(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
Program.StardewInvoke(() => { Program.StardewForm.Show(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_CommandFired(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
StardewValley.SaveGame.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_CommandFired(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
Game1.activeClickableMenu = new StardewValley.Menus.LoadGameMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exit_CommandFired(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
Program.gamePtr.Exit();
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setName(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 1)
|
||||||
|
{
|
||||||
|
string obj = e.Command.CalledArgs[0];
|
||||||
|
string[] objs = "player,pet,farm".Split(new[] { ',' });
|
||||||
|
if (objs.Contains(obj))
|
||||||
|
{
|
||||||
|
switch (obj)
|
||||||
|
{
|
||||||
|
case "player":
|
||||||
|
Game1.player.Name = e.Command.CalledArgs[1];
|
||||||
|
break;
|
||||||
|
case "pet":
|
||||||
|
Log.Error("Pets cannot currently be renamed.");
|
||||||
|
break;
|
||||||
|
case "farm":
|
||||||
|
Game1.player.farmName = e.Command.CalledArgs[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectInvalid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setMoney(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0] == "inf")
|
||||||
|
{
|
||||||
|
infMoney = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
infMoney = false;
|
||||||
|
int ou = 0;
|
||||||
|
if (Int32.TryParse(e.Command.CalledArgs[0], out ou))
|
||||||
|
{
|
||||||
|
Game1.player.Money = ou;
|
||||||
|
Log.Verbose("Set {0}'s money to {1}", Game1.player.Name, Game1.player.Money);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setStamina(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0] == "inf")
|
||||||
|
{
|
||||||
|
infStamina = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
infStamina = false;
|
||||||
|
int ou = 0;
|
||||||
|
if (Int32.TryParse(e.Command.CalledArgs[0], out ou))
|
||||||
|
{
|
||||||
|
Game1.player.Stamina = ou;
|
||||||
|
Log.Verbose("Set {0}'s stamina to {1}", Game1.player.Name, Game1.player.Stamina);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setMaxStamina(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
int ou = 0;
|
||||||
|
if (Int32.TryParse(e.Command.CalledArgs[0], out ou))
|
||||||
|
{
|
||||||
|
Game1.player.MaxStamina = ou;
|
||||||
|
Log.Verbose("Set {0}'s max stamina to {1}", Game1.player.Name, Game1.player.MaxStamina);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setLevel(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 1)
|
||||||
|
{
|
||||||
|
string skill = e.Command.CalledArgs[0];
|
||||||
|
string[] skills = "luck,mining,combat,farming,fishing,foraging".Split(new[] { ',' });
|
||||||
|
if (skills.Contains(skill))
|
||||||
|
{
|
||||||
|
int ou = 0;
|
||||||
|
if (Int32.TryParse(e.Command.CalledArgs[1], out ou))
|
||||||
|
{
|
||||||
|
switch (skill)
|
||||||
|
{
|
||||||
|
case "luck":
|
||||||
|
Game1.player.LuckLevel = ou;
|
||||||
|
break;
|
||||||
|
case "mining":
|
||||||
|
Game1.player.MiningLevel = ou;
|
||||||
|
break;
|
||||||
|
case "combat":
|
||||||
|
Game1.player.CombatLevel = ou;
|
||||||
|
break;
|
||||||
|
case "farming":
|
||||||
|
Game1.player.FarmingLevel = ou;
|
||||||
|
break;
|
||||||
|
case "fishing":
|
||||||
|
Game1.player.FishingLevel = ou;
|
||||||
|
break;
|
||||||
|
case "foraging":
|
||||||
|
Game1.player.ForagingLevel = ou;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<skill> is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<skill> and <value> must be specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setSpeed(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
Game1.player.addedSpeed = e.Command.CalledArgs[0].AsInt32();
|
||||||
|
Log.Verbose("Set {0}'s added speed to {1}", Game1.player.Name, Game1.player.addedSpeed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_changeColour(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 1)
|
||||||
|
{
|
||||||
|
string obj = e.Command.CalledArgs[0];
|
||||||
|
string[] objs = "hair,eyes,pants".Split(new[] { ',' });
|
||||||
|
if (objs.Contains(obj))
|
||||||
|
{
|
||||||
|
string[] cs = e.Command.CalledArgs[1].Split(new[] { ',' }, 3);
|
||||||
|
if (cs[0].IsInt32() && cs[1].IsInt32() && cs[2].IsInt32())
|
||||||
|
{
|
||||||
|
Color c = new Color(cs[0].AsInt32(), cs[1].AsInt32(), cs[2].AsInt32());
|
||||||
|
switch (obj)
|
||||||
|
{
|
||||||
|
case "hair":
|
||||||
|
Game1.player.hairstyleColor = c;
|
||||||
|
break;
|
||||||
|
case "eyes":
|
||||||
|
Game1.player.changeEyeColor(c);
|
||||||
|
break;
|
||||||
|
case "pants":
|
||||||
|
Game1.player.pantsColor = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<colour> is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectInvalid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<object> and <colour> must be specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_changeStyle(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 1)
|
||||||
|
{
|
||||||
|
string obj = e.Command.CalledArgs[0];
|
||||||
|
string[] objs = "hair,shirt,skin,acc,shoe,swim,gender".Split(new[] { ',' });
|
||||||
|
if (objs.Contains(obj))
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[1].IsInt32())
|
||||||
|
{
|
||||||
|
int i = e.Command.CalledArgs[1].AsInt32();
|
||||||
|
switch (obj)
|
||||||
|
{
|
||||||
|
case "hair":
|
||||||
|
Game1.player.changeHairStyle(i);
|
||||||
|
break;
|
||||||
|
case "shirt":
|
||||||
|
Game1.player.changeShirt(i);
|
||||||
|
break;
|
||||||
|
case "acc":
|
||||||
|
Game1.player.changeAccessory(i);
|
||||||
|
break;
|
||||||
|
case "skin":
|
||||||
|
Game1.player.changeSkinColor(i);
|
||||||
|
break;
|
||||||
|
case "shoe":
|
||||||
|
Game1.player.changeShoeColor(i);
|
||||||
|
break;
|
||||||
|
case "swim":
|
||||||
|
if (i == 0)
|
||||||
|
Game1.player.changeOutOfSwimSuit();
|
||||||
|
else if (i == 1)
|
||||||
|
Game1.player.changeIntoSwimsuit();
|
||||||
|
else
|
||||||
|
Log.Error("<value> must be 0 or 1 for this <object>");
|
||||||
|
break;
|
||||||
|
case "gender":
|
||||||
|
if (i == 0)
|
||||||
|
Game1.player.changeGender(true);
|
||||||
|
else if (i == 1)
|
||||||
|
Game1.player.changeGender(false);
|
||||||
|
else
|
||||||
|
Log.Error("<value> must be 0 or 1 for this <object>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueInvalid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectInvalid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void world_freezeTime(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].AsInt32() == 0 || e.Command.CalledArgs[0].AsInt32() == 1)
|
||||||
|
{
|
||||||
|
freezeTime = e.Command.CalledArgs[0].AsInt32() == 1;
|
||||||
|
frozenTime = freezeTime ? Game1.timeOfDay : 0;
|
||||||
|
Log.Verbose("Time is now " + (freezeTime ? "frozen" : "thawed"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<value> should be 0 or 1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void world_setTime(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].AsInt32() <= 2600 && e.Command.CalledArgs[0].AsInt32() >= 600)
|
||||||
|
{
|
||||||
|
Game1.timeOfDay = e.Command.CalledArgs[0].AsInt32();
|
||||||
|
frozenTime = freezeTime ? Game1.timeOfDay : 0;
|
||||||
|
Log.Verbose("Time set to: " + Game1.timeOfDay);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<value> should be between 600 and 2600 (06:00 AM - 02:00 AM [NEXT DAY])");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void world_setDay(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].AsInt32() <= 28 && e.Command.CalledArgs[0].AsInt32() > 0)
|
||||||
|
{
|
||||||
|
Game1.dayOfMonth = e.Command.CalledArgs[0].AsInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Verbose("<value> must be between 1 and 28");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void world_setSeason(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
string obj = e.Command.CalledArgs[0];
|
||||||
|
string[] objs = "winter,spring,summer,fall".Split(new[] { ',' });
|
||||||
|
if (objs.Contains(obj))
|
||||||
|
{
|
||||||
|
Game1.currentSeason = obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueInvalid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setHealth(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0] == "inf")
|
||||||
|
{
|
||||||
|
infHealth = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
infHealth = false;
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
Game1.player.health = e.Command.CalledArgs[0].AsInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setMaxHealth(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
Game1.player.maxHealth = e.Command.CalledArgs[0].AsInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_setImmunity(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
Game1.player.immunity = e.Command.CalledArgs[0].AsInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_addItem(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
int count = 1;
|
||||||
|
int quality = 0;
|
||||||
|
if (e.Command.CalledArgs.Length > 1)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e.Command.CalledArgs[1]);
|
||||||
|
if (e.Command.CalledArgs[1].IsInt32())
|
||||||
|
{
|
||||||
|
count = e.Command.CalledArgs[1].AsInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("[count] is invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Command.CalledArgs.Length > 2)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[2].IsInt32())
|
||||||
|
{
|
||||||
|
quality = e.Command.CalledArgs[2].AsInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("[quality] is invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StardewValley.Object o = new StardewValley.Object(e.Command.CalledArgs[0].AsInt32(), count);
|
||||||
|
o.quality = quality;
|
||||||
|
|
||||||
|
Game1.player.addItemByMenuIfNecessary((Item)o);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<item> is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_addMelee(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
|
||||||
|
MeleeWeapon toAdd = new MeleeWeapon(e.Command.CalledArgs[0].AsInt32());
|
||||||
|
Game1.player.addItemByMenuIfNecessary(toAdd);
|
||||||
|
Log.Verbose("Given {0} to {1}", toAdd.Name, Game1.player.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<item> is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void player_addRing(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
|
||||||
|
Ring toAdd = new Ring(e.Command.CalledArgs[0].AsInt32());
|
||||||
|
Game1.player.addItemByMenuIfNecessary(toAdd);
|
||||||
|
Log.Verbose("Given {0} to {1}", toAdd.Name, Game1.player.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("<item> is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogObjectValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void out_items(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Item it = new StardewValley.Object(i, 1);
|
||||||
|
if (it.Name != "Error Item")
|
||||||
|
Console.WriteLine(i + "| " + it.Name);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void out_melee(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
Dictionary<int, string> d = Game1.content.Load<Dictionary<int, string>>("Data\\weapons");
|
||||||
|
Console.Write("DATA\\WEAPONS: ");
|
||||||
|
foreach (var v in d)
|
||||||
|
{
|
||||||
|
Console.WriteLine(v.Key + " | " + v.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void out_rings(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Item it = new Ring(i);
|
||||||
|
if (it.Name != "Error Item")
|
||||||
|
Console.WriteLine(i + "| " + it.Name);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void world_downMineLevel(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
Game1.nextMineLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void world_setMineLevel(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs.Length > 0)
|
||||||
|
{
|
||||||
|
if (e.Command.CalledArgs[0].IsInt32())
|
||||||
|
{
|
||||||
|
Game1.enterMine(true, e.Command.CalledArgs[0].AsInt32(), "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.LogValueNotSpecified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blank_command(object sender, EventArgsCommand e) { }
|
||||||
|
|
||||||
|
static void RegisterNewItem(object sender, EventArgsCommand e)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
SObject s = SGame.PullModItemFromDict(0, true);
|
||||||
|
s.Stack = 999;
|
||||||
|
Game1.player.addItemToInventory(s);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{28480467-1A48-46A7-99F8-236D95225359}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>TrainerMod</RootNamespace>
|
||||||
|
<AssemblyName>TrainerMod</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>..\StardewModdingAPI\bin\x86\Debug\Mods\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(SteamInstallPath)' != ''">
|
||||||
|
<PropertyGroup>
|
||||||
|
<SteamPath>$(SteamInstallPath)</SteamPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SteamPath>..\..\..\..\Games\SteamLibrary</SteamPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Stardew Valley">
|
||||||
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\Stardew Valley.exe</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="xTile">
|
||||||
|
<HintPath>..\..\..\..\Games\SteamLibrary\steamapps\common\Stardew Valley\xTile.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="TrainerMod.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\StardewModdingAPI\StardewModdingAPI.csproj">
|
||||||
|
<Project>{f1a573b0-f436-472c-ae29-0b91ea6b9f8f}</Project>
|
||||||
|
<Name>StardewModdingAPI</Name>
|
||||||
|
<Private>False</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<PostBuildEvent>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</PropertyGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,538 @@
|
||||||
|
0| Weeds
|
||||||
|
2| Stone
|
||||||
|
4| Stone
|
||||||
|
16| Wild Horseradish
|
||||||
|
18| Daffodil
|
||||||
|
20| Leek
|
||||||
|
22| Dandelion
|
||||||
|
24| Parsnip
|
||||||
|
30| Lumber
|
||||||
|
60| Emerald
|
||||||
|
62| Aquamarine
|
||||||
|
64| Ruby
|
||||||
|
66| Amethyst
|
||||||
|
68| Topaz
|
||||||
|
70| Jade
|
||||||
|
72| Diamond
|
||||||
|
74| Prismatic Shard
|
||||||
|
78| Cave Carrot
|
||||||
|
80| Quartz
|
||||||
|
82| Fire Quartz
|
||||||
|
84| Frozen Tear
|
||||||
|
86| Earth Crystal
|
||||||
|
88| Coconut
|
||||||
|
90| Cactus Fruit
|
||||||
|
92| Sap
|
||||||
|
96| Dwarf Scroll I
|
||||||
|
97| Dwarf Scroll II
|
||||||
|
98| Dwarf Scroll III
|
||||||
|
99| Dwarf Scroll IV
|
||||||
|
100| Chipped Amphora
|
||||||
|
101| Arrowhead
|
||||||
|
102| Lost Book
|
||||||
|
103| Ancient Doll
|
||||||
|
104| Elvish Jewelry
|
||||||
|
105| Chewing Stick
|
||||||
|
106| Ornamental Fan
|
||||||
|
107| Dinosaur Egg
|
||||||
|
108| Rare Disc
|
||||||
|
109| Ancient Sword
|
||||||
|
110| Rusty Spoon
|
||||||
|
111| Rusty Spur
|
||||||
|
112| Rusty Cog
|
||||||
|
113| Chicken Statue
|
||||||
|
114| Ancient Seed
|
||||||
|
115| Prehistoric Tool
|
||||||
|
116| Dried Starfish
|
||||||
|
117| Anchor
|
||||||
|
118| Glass Shards
|
||||||
|
119| Bone Flute
|
||||||
|
120| Prehistoric Handaxe
|
||||||
|
121| Dwarvish Helm
|
||||||
|
122| Dwarf Gadget
|
||||||
|
123| Ancient Drum
|
||||||
|
124| Golden Mask
|
||||||
|
125| Golden Relic
|
||||||
|
126| Strange Doll
|
||||||
|
127| Strange Doll
|
||||||
|
128| Pufferfish
|
||||||
|
129| Anchovy
|
||||||
|
130| Tuna
|
||||||
|
131| Sardine
|
||||||
|
132| Bream
|
||||||
|
136| Largemouth Bass
|
||||||
|
137| Smallmouth Bass
|
||||||
|
138| Rainbow Trout
|
||||||
|
139| Salmon
|
||||||
|
140| Walleye
|
||||||
|
141| Perch
|
||||||
|
142| Carp
|
||||||
|
143| Catfish
|
||||||
|
144| Pike
|
||||||
|
145| Sunfish
|
||||||
|
146| Red Mullet
|
||||||
|
147| Herring
|
||||||
|
148| Eel
|
||||||
|
149| Octopus
|
||||||
|
150| Red Snapper
|
||||||
|
151| Squid
|
||||||
|
152| Seaweed
|
||||||
|
153| Green Algae
|
||||||
|
154| Sea Cucumber
|
||||||
|
155| Super Cucumber
|
||||||
|
156| Ghostfish
|
||||||
|
157| White Algae
|
||||||
|
158| Stonefish
|
||||||
|
159| Crimsonfish
|
||||||
|
160| Angler
|
||||||
|
161| Ice Pip
|
||||||
|
162| Lava Eel
|
||||||
|
163| Legend
|
||||||
|
164| Sandfish
|
||||||
|
165| Scorpion Carp
|
||||||
|
166| Treasure Chest
|
||||||
|
167| Joja Cola
|
||||||
|
168| Trash
|
||||||
|
169| Driftwood
|
||||||
|
170| Broken Glasses
|
||||||
|
171| Broken CD
|
||||||
|
172| Soggy Newspaper
|
||||||
|
174| Large Egg
|
||||||
|
176| Egg
|
||||||
|
178| Hay
|
||||||
|
180| Egg
|
||||||
|
182| Large Egg
|
||||||
|
184| Milk
|
||||||
|
186| Large Milk
|
||||||
|
188| Green Bean
|
||||||
|
190| Cauliflower
|
||||||
|
192| Potato
|
||||||
|
194| Fried Egg
|
||||||
|
195| Omelet
|
||||||
|
196| Salad
|
||||||
|
197| Cheese Cauliflower
|
||||||
|
198| Baked Fish
|
||||||
|
199| Parsnip Soup
|
||||||
|
200| Vegetable Medley
|
||||||
|
201| Complete Breakfast
|
||||||
|
202| Fried Calamari
|
||||||
|
203| Strange Bun
|
||||||
|
204| Lucky Lunch
|
||||||
|
205| Fried Mushroom
|
||||||
|
206| Pizza
|
||||||
|
207| Bean Hotpot
|
||||||
|
208| Glazed Yams
|
||||||
|
209| Carp Surprise
|
||||||
|
210| Hashbrowns
|
||||||
|
211| Pancakes
|
||||||
|
212| Salmon Dinner
|
||||||
|
213| Fish Taco
|
||||||
|
214| Crispy Bass
|
||||||
|
215| Pepper Poppers
|
||||||
|
216| Bread
|
||||||
|
218| Tom Kha Soup
|
||||||
|
219| Trout Soup
|
||||||
|
220| Chocolate Cake
|
||||||
|
221| Pink Cake
|
||||||
|
222| Rhubarb Pie
|
||||||
|
223| Cookie
|
||||||
|
224| Spaghetti
|
||||||
|
225| Fried Eel
|
||||||
|
226| Spicy Eel
|
||||||
|
227| Sashimi
|
||||||
|
228| Maki Roll
|
||||||
|
229| Tortilla
|
||||||
|
230| Red Plate
|
||||||
|
231| Eggplant Parmesan
|
||||||
|
232| Rice Pudding
|
||||||
|
233| Ice Cream
|
||||||
|
234| Blueberry Tart
|
||||||
|
235| Autumn's Bounty
|
||||||
|
236| Pumpkin Soup
|
||||||
|
237| Super Meal
|
||||||
|
238| Cranberry Sauce
|
||||||
|
239| Stuffing
|
||||||
|
240| Farmer's Lunch
|
||||||
|
241| Survival Burger
|
||||||
|
242| Dish O' The Sea
|
||||||
|
243| Miner's Treat
|
||||||
|
244| Roots Platter
|
||||||
|
245| Sugar
|
||||||
|
246| Wheat Flour
|
||||||
|
247| Oil
|
||||||
|
248| Garlic
|
||||||
|
250| Kale
|
||||||
|
252| Rhubarb
|
||||||
|
254| Melon
|
||||||
|
256| Tomato
|
||||||
|
257| Morel
|
||||||
|
258| Blueberry
|
||||||
|
259| Fiddlehead Fern
|
||||||
|
260| Hot Pepper
|
||||||
|
262| Wheat
|
||||||
|
264| Radish
|
||||||
|
266| Red Cabbage
|
||||||
|
268| Starfruit
|
||||||
|
270| Corn
|
||||||
|
272| Eggplant
|
||||||
|
274| Artichoke
|
||||||
|
276| Pumpkin
|
||||||
|
278| Bok Choy
|
||||||
|
280| Yam
|
||||||
|
281| Chanterelle
|
||||||
|
282| Cranberries
|
||||||
|
283| Holly
|
||||||
|
284| Beet
|
||||||
|
286| Cherry Bomb
|
||||||
|
287| Bomb
|
||||||
|
288| Mega Bomb
|
||||||
|
290| Stone
|
||||||
|
294| Twig
|
||||||
|
295| Twig
|
||||||
|
296| Salmonberry
|
||||||
|
297| Grass Starter
|
||||||
|
298| Hardwood Fence
|
||||||
|
299| Amaranth Seeds
|
||||||
|
300| Amaranth
|
||||||
|
301| Grape Starter
|
||||||
|
302| Hops Starter
|
||||||
|
303| Pale Ale
|
||||||
|
304| Hops
|
||||||
|
305| Void Egg
|
||||||
|
306| Mayonnaise
|
||||||
|
307| Duck Mayonnaise
|
||||||
|
309| Acorn
|
||||||
|
310| Maple Seed
|
||||||
|
311| Pine Cone
|
||||||
|
313| Weeds
|
||||||
|
314| Weeds
|
||||||
|
315| Weeds
|
||||||
|
316| Weeds
|
||||||
|
317| Weeds
|
||||||
|
318| Weeds
|
||||||
|
319| Weeds
|
||||||
|
320| Weeds
|
||||||
|
321| Weeds
|
||||||
|
322| Wood Fence
|
||||||
|
323| Stone Fence
|
||||||
|
324| Iron Fence
|
||||||
|
325| Gate
|
||||||
|
326| Dwarvish Translation Guide
|
||||||
|
328| Wood Floor
|
||||||
|
329| Stone Floor
|
||||||
|
330| Clay
|
||||||
|
331| Weathered Floor
|
||||||
|
333| Crystal Floor
|
||||||
|
334| Copper Bar
|
||||||
|
335| Iron Bar
|
||||||
|
336| Gold Bar
|
||||||
|
337| Iridium Bar
|
||||||
|
338| Refined Quartz
|
||||||
|
340| Honey
|
||||||
|
341| Tea Set
|
||||||
|
342| Pickles
|
||||||
|
343| Stone
|
||||||
|
344| Jelly
|
||||||
|
346| Beer
|
||||||
|
347| Rare Seed
|
||||||
|
348| Wine
|
||||||
|
349| Energy Tonic
|
||||||
|
350| Juice
|
||||||
|
351| Muscle Remedy
|
||||||
|
368| Basic Fertilizer
|
||||||
|
369| Quality Fertilizer
|
||||||
|
370| Basic Retaining Soil
|
||||||
|
371| Quality Retaining Soil
|
||||||
|
372| Clam
|
||||||
|
373| Golden Pumpkin
|
||||||
|
376| Poppy
|
||||||
|
378| Copper Ore
|
||||||
|
380| Iron Ore
|
||||||
|
382| Coal
|
||||||
|
384| Gold Ore
|
||||||
|
386| Iridium Ore
|
||||||
|
388| Wood
|
||||||
|
390| Stone
|
||||||
|
392| Nautilus Shell
|
||||||
|
393| Coral
|
||||||
|
394| Rainbow Shell
|
||||||
|
395| Coffee
|
||||||
|
396| Spice Berry
|
||||||
|
397| Sea Urchin
|
||||||
|
398| Grape
|
||||||
|
399| Spring Onion
|
||||||
|
400| Strawberry
|
||||||
|
401| Straw Floor
|
||||||
|
402| Sweet Pea
|
||||||
|
403| Field Snack
|
||||||
|
404| Common Mushroom
|
||||||
|
405| Wood Path
|
||||||
|
406| Wild Plum
|
||||||
|
407| Gravel Path
|
||||||
|
408| Hazelnut
|
||||||
|
409| Crystal Path
|
||||||
|
410| Blackberry
|
||||||
|
411| Cobblestone Path
|
||||||
|
412| Winter Root
|
||||||
|
413| Blue Slime Egg
|
||||||
|
414| Crystal Fruit
|
||||||
|
416| Snow Yam
|
||||||
|
417| Sweet Gem Berry
|
||||||
|
418| Crocus
|
||||||
|
419| Vinegar
|
||||||
|
420| Red Mushroom
|
||||||
|
421| Sunflower
|
||||||
|
422| Purple Mushroom
|
||||||
|
423| Rice
|
||||||
|
424| Cheese
|
||||||
|
425| Fairy Seeds
|
||||||
|
426| Goat Cheese
|
||||||
|
427| Tulip Bulb
|
||||||
|
428| Cloth
|
||||||
|
429| Jazz Seeds
|
||||||
|
430| Truffle
|
||||||
|
431| Sunflower Seeds
|
||||||
|
432| Truffle Oil
|
||||||
|
434| Stardrop
|
||||||
|
436| Goat Milk
|
||||||
|
437| Red Slime Egg
|
||||||
|
438| L. Goat Milk
|
||||||
|
439| Purple Slime Egg
|
||||||
|
440| Wool
|
||||||
|
441| Explosive Ammo
|
||||||
|
442| Duck Egg
|
||||||
|
444| Duck Feather
|
||||||
|
446| Rabbit's Foot
|
||||||
|
449| Stone Base
|
||||||
|
450| Stone
|
||||||
|
452| Weeds
|
||||||
|
453| Poppy Seeds
|
||||||
|
454| Ancient Fruit
|
||||||
|
455| Spangle Seeds
|
||||||
|
456| Algae Soup
|
||||||
|
457| Pale Broth
|
||||||
|
458| Bouquet
|
||||||
|
460| Mermaid's Pendant
|
||||||
|
461| Decorative Pot
|
||||||
|
463| Drum Block
|
||||||
|
464| Flute Block
|
||||||
|
465| Speed-Gro
|
||||||
|
466| Deluxe Speed-Gro
|
||||||
|
472| Parsnip Seeds
|
||||||
|
473| Bean Starter
|
||||||
|
474| Cauliflower Seeds
|
||||||
|
475| Potato Seeds
|
||||||
|
476| Garlic Seeds
|
||||||
|
477| Kale Seeds
|
||||||
|
478| Rhubarb Seeds
|
||||||
|
479| Melon Seeds
|
||||||
|
480| Tomato Seeds
|
||||||
|
481| Blueberry Seeds
|
||||||
|
482| Pepper Seeds
|
||||||
|
483| Wheat Seeds
|
||||||
|
484| Radish Seeds
|
||||||
|
485| Red Cabbage Seeds
|
||||||
|
486| Starfruit Seeds
|
||||||
|
487| Corn Seeds
|
||||||
|
488| Eggplant Seeds
|
||||||
|
489| Artichoke Seeds
|
||||||
|
490| Pumpkin Seeds
|
||||||
|
491| Bok Choy Seeds
|
||||||
|
492| Yam Seeds
|
||||||
|
493| Cranberry Seeds
|
||||||
|
494| Beet Seeds
|
||||||
|
495| Spring Seeds
|
||||||
|
496| Summer Seeds
|
||||||
|
497| Fall Seeds
|
||||||
|
498| Winter Seeds
|
||||||
|
499| Ancient Seeds
|
||||||
|
516| Small Glow Ring
|
||||||
|
517| Glow Ring
|
||||||
|
518| Small Magnet Ring
|
||||||
|
519| Magnet Ring
|
||||||
|
520| Slime Charmer Ring
|
||||||
|
521| Warrior Ring
|
||||||
|
522| Vampire Ring
|
||||||
|
523| Savage Ring
|
||||||
|
524| Ring of Yoba
|
||||||
|
525| Sturdy Ring
|
||||||
|
526| Burglar's Ring
|
||||||
|
527| Iridium Band
|
||||||
|
528| Jukebox Ring
|
||||||
|
529| Amethyst Ring
|
||||||
|
530| Topaz Ring
|
||||||
|
531| Aquamarine Ring
|
||||||
|
532| Jade Ring
|
||||||
|
533| Emerald Ring
|
||||||
|
534| Ruby Ring
|
||||||
|
535| Geode
|
||||||
|
536| Frozen Geode
|
||||||
|
537| Magma Geode
|
||||||
|
538| Alamite
|
||||||
|
539| Bixite
|
||||||
|
540| Baryte
|
||||||
|
541| Aerinite
|
||||||
|
542| Calcite
|
||||||
|
543| Dolomite
|
||||||
|
544| Esperite
|
||||||
|
545| Fluorapatite
|
||||||
|
546| Geminite
|
||||||
|
547| Helvite
|
||||||
|
548| Jamborite
|
||||||
|
549| Jagoite
|
||||||
|
550| Kyanite
|
||||||
|
551| Lunarite
|
||||||
|
552| Malachite
|
||||||
|
553| Neptunite
|
||||||
|
554| Lemon Stone
|
||||||
|
555| Nekoite
|
||||||
|
556| Orpiment
|
||||||
|
557| Petrified Slime
|
||||||
|
558| Thunder Egg
|
||||||
|
559| Pyrite
|
||||||
|
560| Ocean Stone
|
||||||
|
561| Ghost Crystal
|
||||||
|
562| Tigerseye
|
||||||
|
563| Jasper
|
||||||
|
564| Opal
|
||||||
|
565| Fire Opal
|
||||||
|
566| Celestine
|
||||||
|
567| Marble
|
||||||
|
568| Sandstone
|
||||||
|
569| Granite
|
||||||
|
570| Basalt
|
||||||
|
571| Limestone
|
||||||
|
572| Soapstone
|
||||||
|
573| Hematite
|
||||||
|
574| Mudstone
|
||||||
|
575| Obsidian
|
||||||
|
576| Slate
|
||||||
|
577| Fairy Stone
|
||||||
|
578| Star Shards
|
||||||
|
579| Prehistoric Scapula
|
||||||
|
580| Prehistoric Tibia
|
||||||
|
581| Prehistoric Skull
|
||||||
|
582| Skeletal Hand
|
||||||
|
583| Prehistoric Rib
|
||||||
|
584| Prehistoric Vertebra
|
||||||
|
585| Skeletal Tail
|
||||||
|
586| Nautilus Shell
|
||||||
|
587| Amphibian Fossil
|
||||||
|
588| Palm Fossil
|
||||||
|
589| Trilobite
|
||||||
|
590| Artifact Spot
|
||||||
|
591| Tulip
|
||||||
|
593| Summer Spangle
|
||||||
|
595| Fairy Rose
|
||||||
|
597| Blue Jazz
|
||||||
|
599| Sprinkler
|
||||||
|
604| Plum Pudding
|
||||||
|
605| Artichoke Dip
|
||||||
|
606| Stir Fry
|
||||||
|
607| Roasted Hazelnuts
|
||||||
|
608| Pumpkin Pie
|
||||||
|
609| Radish Salad
|
||||||
|
610| Fruit Salad
|
||||||
|
611| Blackberry Cobbler
|
||||||
|
612| Cranberry Candy
|
||||||
|
613| Apple
|
||||||
|
618| Bruschetta
|
||||||
|
621| Quality Sprinkler
|
||||||
|
628| Cherry Sapling
|
||||||
|
629| Apricot Sapling
|
||||||
|
630| Orange Sapling
|
||||||
|
631| Peach Sapling
|
||||||
|
632| Pomegranate Sapling
|
||||||
|
633| Apple Sapling
|
||||||
|
634| Apricot
|
||||||
|
635| Orange
|
||||||
|
636| Peach
|
||||||
|
637| Pomegranate
|
||||||
|
638| Cherry
|
||||||
|
645| Iridium Sprinkler
|
||||||
|
648| Coleslaw
|
||||||
|
649| Fiddlehead Risotto
|
||||||
|
651| Poppyseed Muffin
|
||||||
|
668| Stone
|
||||||
|
670| Stone
|
||||||
|
674| Weeds
|
||||||
|
675| Weeds
|
||||||
|
676| Weeds
|
||||||
|
677| Weeds
|
||||||
|
678| Weeds
|
||||||
|
679| Weeds
|
||||||
|
680| Green Slime Egg
|
||||||
|
681| Rain Totem
|
||||||
|
682| Mutant Carp
|
||||||
|
684| Bug Meat
|
||||||
|
685| Bait
|
||||||
|
686| Spinner
|
||||||
|
687| Dressed Spinner
|
||||||
|
688| Warp Totem: Farm
|
||||||
|
689| Warp Totem: Mountains
|
||||||
|
690| Warp Totem: Beach
|
||||||
|
691| Barbed Hook
|
||||||
|
692| Lead Bobber
|
||||||
|
693| Treasure Hunter
|
||||||
|
694| Trap Bobber
|
||||||
|
695| Cork Bobber
|
||||||
|
698| Sturgeon
|
||||||
|
699| Tiger Trout
|
||||||
|
700| Bullhead
|
||||||
|
701| Tilapia
|
||||||
|
702| Chub
|
||||||
|
703| Magnet
|
||||||
|
704| Dorado
|
||||||
|
705| Albacore
|
||||||
|
706| Shad
|
||||||
|
707| Lingcod
|
||||||
|
708| Halibut
|
||||||
|
709| Hardwood
|
||||||
|
710| Crab Pot
|
||||||
|
715| Lobster
|
||||||
|
716| Crayfish
|
||||||
|
717| Crab
|
||||||
|
718| Cockle
|
||||||
|
719| Mussel
|
||||||
|
720| Shrimp
|
||||||
|
721| Snail
|
||||||
|
722| Periwinkle
|
||||||
|
723| Oyster
|
||||||
|
724| Maple Syrup
|
||||||
|
725| Oak Resin
|
||||||
|
726| Pine Tar
|
||||||
|
727| Chowder
|
||||||
|
728| Fish Stew
|
||||||
|
729| Escargot
|
||||||
|
730| Lobster Bisque
|
||||||
|
731| Maple Bar
|
||||||
|
732| Crab Cakes
|
||||||
|
734| Woodskip
|
||||||
|
745| Strawberry Seeds
|
||||||
|
746| Jack-O-Lantern
|
||||||
|
747| Rotten Plant
|
||||||
|
748| Rotten Plant
|
||||||
|
749| Omni Geode
|
||||||
|
750| Weeds
|
||||||
|
751| Stone
|
||||||
|
760| Stone
|
||||||
|
762| Stone
|
||||||
|
764| Stone
|
||||||
|
765| Stone
|
||||||
|
766| Slime
|
||||||
|
767| Bat Wing
|
||||||
|
768| Solar Essence
|
||||||
|
769| Void Essence
|
||||||
|
770| Mixed Seeds
|
||||||
|
771| Fiber
|
||||||
|
772| Oil of Garlic
|
||||||
|
773| Life Elixir
|
||||||
|
774| Wild Bait
|
||||||
|
775| Glacierfish
|
||||||
|
784| Weeds
|
||||||
|
785| Weeds
|
||||||
|
786| Weeds
|
||||||
|
787| Battery Pack
|
||||||
|
788| Lost Axe
|
||||||
|
789| Lucky Purple Shorts
|
||||||
|
790| Berry Basket
|
|
@ -1,78 +0,0 @@
|
||||||
<!--
|
|
||||||
|
|
||||||
This MSBuild file sets the common configuration and build scripts used by all the projects in this
|
|
||||||
repo. It imports the other MSBuild files as needed.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<!--set general build properties -->
|
|
||||||
<Version>3.18.4</Version>
|
|
||||||
<Product>SMAPI</Product>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<AssemblySearchPaths>$(AssemblySearchPaths);{GAC}</AssemblySearchPaths>
|
|
||||||
<DefineConstants Condition="$(OS) == 'Windows_NT' AND '$(BUILD_FOR_MOBILE)' == ''">$(DefineConstants);SMAPI_DEPRECATED;SMAPI_FOR_WINDOWS</DefineConstants>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
|
|
||||||
<!--embed symbols for error stack trace line numbers on Linux/macOS: https://github.com/dotnet/runtime/issues/39987-->
|
|
||||||
<DebugType>embedded</DebugType>
|
|
||||||
|
|
||||||
<!--enable nullable annotations, except in .NET Standard 2.0 where they aren't supported-->
|
|
||||||
<Nullable Condition="'$(TargetFramework)' != 'netstandard2.0'">enable</Nullable>
|
|
||||||
<NoWarn Condition="'$(TargetFramework)' == 'netstandard2.0'">$(NoWarn);CS8632</NoWarn>
|
|
||||||
|
|
||||||
<!--set platform-->
|
|
||||||
<DefineConstants Condition="$(OS) == 'Windows_NT'">$(DefineConstants);SMAPI_FOR_WINDOWS</DefineConstants>
|
|
||||||
<CopyToGameFolder>false</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.
|
|
||||||
CS0612 | deprecated | member is obsolete | internal references to deprecated code when deprecated code is enabled.
|
|
||||||
CS0618 | deprecated | member is obsolete (with message) | internal references to deprecated code when deprecated code is enabled.
|
|
||||||
CA1416 | all | platform code available on all platforms | Compiler doesn't recognize the #if constants used by SMAPI.
|
|
||||||
CS0809 | all | obsolete overload for non-obsolete 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 Condition="$(DefineConstants.Contains(SMAPI_DEPRECATED))">$(NoWarn);CS0612;CS0618</NoWarn>
|
|
||||||
<NoWarn>$(NoWarn);CS0436;CA1416;CS0809;NU1701</NoWarn>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="$(COMPILE_WITH_PLUGIN) == 'True'">
|
|
||||||
<PackageReference Include="Microsoft.Net.Compilers" Version="3.3.1">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<!--find game folder-->
|
|
||||||
<Import Project="find-game-folder.targets" />
|
|
||||||
<!-- <Target Name="ValidateInstallPath" AfterTargets="BeforeBuild">-->
|
|
||||||
<!-- <!– if game path is invalid, show one user-friendly error instead of a slew of reference errors –>-->
|
|
||||||
<!-- <Error Condition="!Exists('$(GamePath)')" Text="Failed to find the game install path automatically. You can specify where to find it; see https://smapi.io/package/custom-game-path." />-->
|
|
||||||
<!-- </Target>-->
|
|
||||||
|
|
||||||
<!-- common build settings -->
|
|
||||||
<PropertyGroup>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
</PropertyGroup>
|
|
||||||
<!--deploy local files-->
|
|
||||||
<Import Project="deploy-local-smapi.targets" Condition="'$(CopyToGameFolder)' == 'true'" />
|
|
||||||
|
|
||||||
<!-- launch SMAPI through Visual Studio -->
|
|
||||||
<PropertyGroup Condition="'$(MSBuildProjectName)' == 'SMAPI'">
|
|
||||||
<StartAction>Program</StartAction>
|
|
||||||
<StartProgram>$(GamePath)\StardewModdingAPI.exe</StartProgram>
|
|
||||||
<StartWorkingDirectory>$(GamePath)</StartWorkingDirectory>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<!-- Somehow this makes Visual Studio for macOS recognise the previous section. Nobody knows why. -->
|
|
||||||
<PropertyGroup Condition="'$(RunConfiguration)' == 'Default'" />
|
|
||||||
</Project>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<!--set properties -->
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- <BUILD_FOR_MOBILE></BUILD_FOR_MOBILE>-->
|
|
||||||
<BUILD_FOR_MOBILE>GOOGLE</BUILD_FOR_MOBILE>
|
|
||||||
<!-- <BUILD_FOR_MOBILE>GOOGLE_145</BUILD_FOR_MOBILE>-->
|
|
||||||
<!-- <BUILD_FOR_MOBILE>AMAZON</BUILD_FOR_MOBILE>-->
|
|
||||||
<!-- <BUILD_FOR_MOBILE>SAMSUNG</BUILD_FOR_MOBILE>-->
|
|
||||||
<!-- <BUILD_FOR_MOBILE>GOOGLE_LEGACY</BUILD_FOR_MOBILE>-->
|
|
||||||
<COMPILE_WITH_PLUGIN>False</COMPILE_WITH_PLUGIN>
|
|
||||||
<DefineConstants Condition="'$(BUILD_FOR_MOBILE)' == 'GOOGLE'">SMAPI_DEPRECATED;SMAPI_FOR_MOBILE;ANDROID_TARGET_GOOGLE</DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
|
@ -1,77 +0,0 @@
|
||||||
<!--
|
|
||||||
|
|
||||||
This MSBuild file copies SMAPI and the bundled mods into the local Stardew Valley folder on build
|
|
||||||
to simplify testing. This just avoids needing to run the SMAPI installer each time.
|
|
||||||
|
|
||||||
This assumes `find-game-folder.targets` has already been imported and validated.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Target Name="CopySmapiFiles" AfterTargets="AfterBuild">
|
|
||||||
<CallTarget Targets="CopySMAPI;CopyDefaultMods" />
|
|
||||||
</Target>
|
|
||||||
<Target Name="CopySMAPI" Condition="'$(MSBuildProjectName)' == 'SMAPI'">
|
|
||||||
<!-- SMAPI -->
|
|
||||||
<ItemGroup>
|
|
||||||
<TranslationFiles Include="$(TargetDir)\i18n\*.json" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).dll" DestinationFolder="$(GamePath)" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).exe" DestinationFolder="$(GamePath)" Condition="$(OS) == 'Windows_NT'" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName)" DestinationFolder="$(GamePath)" Condition="$(OS) != 'Windows_NT'" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).xml" DestinationFolder="$(GamePath)" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\SMAPI.config.json" DestinationFiles="$(GamePath)\smapi-internal\config.json" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\SMAPI.metadata.json" DestinationFiles="$(GamePath)\smapi-internal\metadata.json" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\Newtonsoft.Json.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\TMXTile.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\Pintail.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="@(TranslationFiles)" DestinationFolder="$(GamePath)\smapi-internal\i18n" />
|
|
||||||
|
|
||||||
<!-- Harmony + dependencies -->
|
|
||||||
<Copy SourceFiles="$(TargetDir)\0Harmony.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\0Harmony.xml" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\Mono.Cecil.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\Mono.Cecil.Mdb.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\Mono.Cecil.Pdb.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\MonoMod.Common.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
|
|
||||||
<!-- FluentHttpClient + dependencies -->
|
|
||||||
<Copy SourceFiles="$(TargetDir)\Pathoschild.Http.Client.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\System.Net.Http.Formatting.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
|
|
||||||
<!-- .NET dependencies -->
|
|
||||||
<Copy SourceFiles="$(TargetDir)\System.Management.dll" DestinationFolder="$(GamePath)\smapi-internal" Condition="$(OS) == 'Windows_NT'" />
|
|
||||||
|
|
||||||
<!-- Legacy .NET dependencies (remove in SMAPI 4.0.0) -->
|
|
||||||
<Copy SourceFiles="$(TargetDir)\System.Configuration.ConfigurationManager.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\System.Runtime.Caching.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\System.Security.Permissions.dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<!-- .NET metadata files -->
|
|
||||||
<Target Name="CopyNetMetadata" Condition="'$(MSBuildProjectName)' == 'SMAPI.Installer'" AfterTargets="PostBuildEvent">
|
|
||||||
<Copy SourceFiles="$(TargetDir)\assets\runtimeconfig.json" DestinationFiles="$(GamePath)\StardewModdingAPI.runtimeconfig.json" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\assets\windows-exe-config.xml" DestinationFiles="$(GamePath)\StardewModdingAPI.exe.config" Condition="$(OS) == 'Windows_NT'" />
|
|
||||||
<Copy SourceFiles="$(GamePath)\Stardew Valley.deps.json" DestinationFiles="$(GamePath)\StardewModdingAPI.deps.json" Condition="!Exists('$(GamePath)\StardewModdingAPI.deps.json')" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<!-- bundled mods -->
|
|
||||||
<Target Name="CopyDefaultMods" Condition="'$(MSBuildProjectName)' == 'SMAPI.Mods.ConsoleCommands' OR '$(MSBuildProjectName)' == 'SMAPI.Mods.ErrorHandler' OR '$(MSBuildProjectName)' == 'SMAPI.Mods.SaveBackup'">
|
|
||||||
<ItemGroup>
|
|
||||||
<TranslationFiles Include="$(TargetDir)\i18n\*.json" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).dll" DestinationFolder="$(GamePath)\Mods\$(AssemblyName)" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\manifest.json" DestinationFolder="$(GamePath)\Mods\$(AssemblyName)" />
|
|
||||||
<Copy SourceFiles="@(TranslationFiles)" DestinationFolder="$(GamePath)\Mods\$(AssemblyName)\i18n" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<!-- toolkit -->
|
|
||||||
<Target Name="CopyToolkit" Condition="'$(MSBuildProjectName)' == 'SMAPI.Toolkit'" AfterTargets="PostBuildEvent">
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).xml" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
</Target>
|
|
||||||
<Target Name="CopyToolkitCoreInterfaces" Condition="'$(MSBuildProjectName)' == 'SMAPI.Toolkit.CoreInterfaces'" AfterTargets="PostBuildEvent">
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).dll" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
<Copy SourceFiles="$(TargetDir)\$(TargetName).xml" DestinationFolder="$(GamePath)\smapi-internal" />
|
|
||||||
</Target>
|
|
||||||
</Project>
|
|
|
@ -1,66 +0,0 @@
|
||||||
<!--
|
|
||||||
|
|
||||||
This MSBuild file detects the Stardew Valley install path if possible, and sets the 'GamePath'
|
|
||||||
property.
|
|
||||||
|
|
||||||
-->
|
|
||||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<!-- import developer's custom path (if any) -->
|
|
||||||
<Import Condition="$(OS) != 'Windows_NT' AND Exists('$(HOME)\stardewvalley.targets')" Project="$(HOME)\stardewvalley.targets" />
|
|
||||||
<Import Condition="$(OS) == 'Windows_NT' AND Exists('$(USERPROFILE)\stardewvalley.targets')" Project="$(USERPROFILE)\stardewvalley.targets" />
|
|
||||||
|
|
||||||
<!-- find game path -->
|
|
||||||
<Choose>
|
|
||||||
<When Condition="$(OS) == 'Unix' OR $(OS) == 'OSX'">
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- Linux -->
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">$(HOME)/GOG Games/Stardew Valley/game</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">$(HOME)/.steam/steam/steamapps/common/Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">$(HOME)/.local/share/Steam/steamapps/common/Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">$(HOME)/.var/app/com.valvesoftware.Steam/data/Steam/steamapps/common/Stardew Valley</GamePath>
|
|
||||||
|
|
||||||
<!-- macOS (may be 'Unix' or 'OSX') -->
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">/Applications/Stardew Valley.app/Contents/MacOS</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">$(HOME)/Library/Application Support/Steam/steamapps/common/Stardew Valley/Contents/MacOS</GamePath>
|
|
||||||
</PropertyGroup>
|
|
||||||
</When>
|
|
||||||
<When Condition="$(OS) == 'Windows_NT'">
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- registry paths -->
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\GOG.com\Games\1453375253', 'PATH', null, RegistryView.Registry32))</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 413150', 'InstallLocation', null, RegistryView.Registry64, RegistryView.Registry32))</GamePath>
|
|
||||||
|
|
||||||
<!-- derive from Steam library path -->
|
|
||||||
<_SteamLibraryPath>$([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Valve\Steam', 'SteamPath', null, RegistryView.Registry32))</_SteamLibraryPath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)') AND '$(_SteamLibraryPath)' != ''">$(_SteamLibraryPath)\steamapps\common\Stardew Valley</GamePath>
|
|
||||||
|
|
||||||
<!-- GOG paths -->
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files\GalaxyClient\Games\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files\GOG Galaxy\Games\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files\GOG Games\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files (x86)\GalaxyClient\Games\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files (x86)\GOG Galaxy\Games\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files (x86)\GOG Games\Stardew Valley</GamePath>
|
|
||||||
|
|
||||||
<!-- Xbox app paths -->
|
|
||||||
<!--
|
|
||||||
The Xbox app saves the install path to the registry, but we can't use it here since it
|
|
||||||
saves the internal readonly path (like C:\Program Files\WindowsApps\Mutable\<package ID>)
|
|
||||||
instead of the mods-enabled path (like C:\Program Files\ModifiableWindowsApps\Stardew Valley).
|
|
||||||
Fortunately we can cheat a bit: players can customize the install drive, but they can't
|
|
||||||
change the install path on the drive.
|
|
||||||
-->
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files\ModifiableWindowsApps\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">D:\Program Files\ModifiableWindowsApps\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">E:\Program Files\ModifiableWindowsApps\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">F:\Program Files\ModifiableWindowsApps\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">G:\Program Files\ModifiableWindowsApps\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">H:\Program Files\ModifiableWindowsApps\Stardew Valley</GamePath>
|
|
||||||
|
|
||||||
<!-- Steam paths -->
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files\Steam\steamapps\common\Stardew Valley</GamePath>
|
|
||||||
<GamePath Condition="!Exists('$(GamePath)')">C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley</GamePath>
|
|
||||||
</PropertyGroup>
|
|
||||||
</When>
|
|
||||||
</Choose>
|
|
||||||
</Project>
|
|
|
@ -1,212 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# This is the Bash equivalent of ../windows/prepare-install-package.ps1.
|
|
||||||
# When making changes, both scripts should be updated.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
##########
|
|
||||||
## Fetch values
|
|
||||||
##########
|
|
||||||
# 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")
|
|
||||||
|
|
||||||
# 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"`/../.."
|
|
||||||
|
|
||||||
|
|
||||||
##########
|
|
||||||
## 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
|
|
||||||
##########
|
|
||||||
. ${0%/*}/set-smapi-version.sh "$version"
|
|
||||||
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.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" "Pathoschild.Http.Client.dll" "Pintail.dll" "TMXTile.dll" "SMAPI.Toolkit.dll" "SMAPI.Toolkit.xml" "SMAPI.Toolkit.CoreInterfaces.dll" "SMAPI.Toolkit.CoreInterfaces.xml" "System.Net.Http.Formatting.dll"; 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"
|
|
||||||
else
|
|
||||||
cp "$installAssets/windows-exe-config.xml" "$bundlePath/StardewModdingAPI.exe.config"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# copy .NET dependencies
|
|
||||||
if [ $folder == "windows" ]; then
|
|
||||||
cp "$smapiBin/System.Management.dll" "$bundlePath/smapi-internal"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# copy legacy .NET dependencies (remove in SMAPI 4.0.0)
|
|
||||||
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"
|
|
||||||
|
|
||||||
# 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/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
|
|
||||||
##########
|
|
||||||
# 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"
|
|
|
@ -1,26 +0,0 @@
|
||||||
#!/usr/bin/env 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
|
|
|
@ -1,67 +0,0 @@
|
||||||
#!/usr/bin/env 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!"
|
|
|
@ -1,11 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
|
@ -1,241 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# 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 (unless you specify
|
|
||||||
# --windows-only). 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"
|
|
||||||
|
|
||||||
|
|
||||||
##########
|
|
||||||
## Fetch values
|
|
||||||
##########
|
|
||||||
# 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" }
|
|
||||||
|
|
||||||
# version number
|
|
||||||
$version = $args[0]
|
|
||||||
if (!$version) {
|
|
||||||
$version = Read-Host "SMAPI release version (like '4.0.0')"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Windows-only build
|
|
||||||
$windowsOnly = $false
|
|
||||||
foreach ($arg in $args) {
|
|
||||||
if ($arg -eq "--windows-only") {
|
|
||||||
$windowsOnly = $true
|
|
||||||
$folders = "windows"
|
|
||||||
$runtimes = @{ windows = "win-x64" }
|
|
||||||
$msBuildPlatformNames = @{ 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
|
|
||||||
##########
|
|
||||||
. "$PSScriptRoot/set-smapi-version.ps1" "$version"
|
|
||||||
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")) {
|
|
||||||
if ($windowsOnly -and ($name -eq "install on Linux.sh" -or $name -eq "install on macOS.command")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.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", "Pathoschild.Http.Client.dll", "Pintail.dll", "TMXTile.dll", "SMAPI.Toolkit.dll", "SMAPI.Toolkit.xml", "SMAPI.Toolkit.CoreInterfaces.dll", "SMAPI.Toolkit.CoreInterfaces.xml", "System.Net.Http.Formatting.dll")) {
|
|
||||||
cp "$smapiBin/$name" "$bundlePath/smapi-internal"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($folder -eq "windows") {
|
|
||||||
cp "$smapiBin/VdfConverter.dll" "$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"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cp "$installAssets/windows-exe-config.xml" "$bundlePath/StardewModdingAPI.exe.config"
|
|
||||||
}
|
|
||||||
|
|
||||||
# copy .NET dependencies
|
|
||||||
if ($folder -eq "windows") {
|
|
||||||
cp "$smapiBin/System.Management.dll" "$bundlePath/smapi-internal"
|
|
||||||
}
|
|
||||||
|
|
||||||
# copy legacy .NET dependencies (remove in SMAPI 4.0.0)
|
|
||||||
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"
|
|
||||||
|
|
||||||
# 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/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"
|
|
||||||
|
|
||||||
# convert bundle folder into final 'install.dat' files
|
|
||||||
if ($windowsOnly)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
###########
|
|
||||||
# rename folders
|
|
||||||
mv "$packagePath" "bin/SMAPI $version installer"
|
|
||||||
mv "$packageDevPath" "bin/SMAPI $version installer for developers"
|
|
||||||
|
|
||||||
# package files
|
|
||||||
if ($windowsOnly)
|
|
||||||
{
|
|
||||||
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."
|
|
|
@ -1,25 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# 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`""
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
**SMAPI** is an open-source modding framework and API for [Stardew Valley](https://stardewvalley.net/)
|
|
||||||
that lets you play the game with mods. It's safely installed alongside the game's executable, and
|
|
||||||
doesn't change any of your game files. It serves seven main purposes:
|
|
||||||
|
|
||||||
1. **Load mods into the game.**
|
|
||||||
_SMAPI loads mods when the game is starting up so they can interact with it. (Code mods aren't
|
|
||||||
possible without SMAPI to load them.)_
|
|
||||||
|
|
||||||
2. **Provide APIs and events for mods.**
|
|
||||||
_SMAPI provides APIs and events which let mods interact with the game in ways they otherwise
|
|
||||||
couldn't._
|
|
||||||
|
|
||||||
3. **Rewrite mods for compatibility.**
|
|
||||||
_SMAPI rewrites mods' compiled code before loading them so they work on Linux/macOS/Windows
|
|
||||||
without the mods needing to handle differences between the Linux/macOS and Windows versions of
|
|
||||||
the game. In some cases it also rewrites code broken by a game update so the mod doesn't break._
|
|
||||||
|
|
||||||
5. **Intercept errors and automatically fix saves.**
|
|
||||||
_SMAPI intercepts errors, shows the error info in the SMAPI console, and in most cases
|
|
||||||
automatically recovers the game. That prevents mods from crashing the game, and makes it
|
|
||||||
possible to troubleshoot errors in the game itself that would otherwise show a generic 'program
|
|
||||||
has stopped working' type of message._
|
|
||||||
|
|
||||||
_SMAPI also automatically fixes save data in some cases when a load would crash, e.g. due to a
|
|
||||||
custom location or NPC mod that was removed._
|
|
||||||
|
|
||||||
6. **Provide update checks.**
|
|
||||||
_SMAPI automatically checks for new versions of your installed mods, and notifies you when any
|
|
||||||
are available._
|
|
||||||
|
|
||||||
7. **Provide compatibility checks.**
|
|
||||||
_SMAPI automatically detects outdated or broken code in mods, and safely disables them before
|
|
||||||
they cause problems._
|
|
||||||
|
|
||||||
8. **Back up your save files.**
|
|
||||||
_SMAPI automatically creates a daily backup of your saves and keeps ten backups (via the bundled
|
|
||||||
Save Backup mod), in case something goes wrong._
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
Have questions? Come [ask the community](https://smapi.io/community) to get help from SMAPI
|
|
||||||
developers and other modders!
|
|
||||||
|
|
||||||
### For players
|
|
||||||
* [Player guide](https://stardewvalleywiki.com/Modding:Player_Guide)
|
|
||||||
|
|
||||||
### For modders
|
|
||||||
* [Modding documentation](https://smapi.io/docs)
|
|
||||||
* [Mod build configuration](technical/mod-package.md)
|
|
||||||
* [Release notes](release-notes.md)
|
|
||||||
|
|
||||||
### For SMAPI developers
|
|
||||||
* [Technical docs](technical/smapi.md)
|
|
||||||
|
|
||||||
## Translating SMAPI
|
|
||||||
SMAPI rarely shows text in-game, so it only has a few translations. Contributions are welcome! See
|
|
||||||
[Modding:Translations](https://stardewvalleywiki.com/Modding:Translations) on the wiki for help
|
|
||||||
contributing translations.
|
|
||||||
|
|
||||||
locale | status
|
|
||||||
----------- | :----------------
|
|
||||||
default | ✓ [fully translated](../src/SMAPI/i18n/default.json)
|
|
||||||
Chinese | ✓ [fully translated](../src/SMAPI/i18n/zh.json)
|
|
||||||
French | ✓ [fully translated](../src/SMAPI/i18n/fr.json)
|
|
||||||
German | ✓ [fully translated](../src/SMAPI/i18n/de.json)
|
|
||||||
Hungarian | ✓ [fully translated](../src/SMAPI/i18n/hu.json)
|
|
||||||
Italian | ✓ [fully translated](../src/SMAPI/i18n/it.json)
|
|
||||||
Japanese | ✓ [fully translated](../src/SMAPI/i18n/ja.json)
|
|
||||||
Korean | ✓ [fully translated](../src/SMAPI/i18n/ko.json)
|
|
||||||
[Polish] | ✓ [fully translated](../src/SMAPI/i18n/pl.json)
|
|
||||||
Portuguese | ✓ [fully translated](../src/SMAPI/i18n/pt.json)
|
|
||||||
Russian | ✓ [fully translated](../src/SMAPI/i18n/ru.json)
|
|
||||||
Spanish | ✓ [fully translated](../src/SMAPI/i18n/es.json)
|
|
||||||
[Thai] | ✓ [fully translated](../src/SMAPI/i18n/th.json)
|
|
||||||
Turkish | ✓ [fully translated](../src/SMAPI/i18n/tr.json)
|
|
||||||
[Ukrainian] | ✓ [fully translated](../src/SMAPI/i18n/uk.json)
|
|
||||||
|
|
||||||
[Polish]: https://www.nexusmods.com/stardewvalley/mods/3616
|
|
||||||
[Thai]: https://www.nexusmods.com/stardewvalley/mods/7052
|
|
||||||
[Ukrainian]: https://www.nexusmods.com/stardewvalley/mods/8427
|
|
|
@ -1 +0,0 @@
|
||||||
[Documentation moved](technical/mod-package.md).
|
|
|
@ -1,618 +0,0 @@
|
||||||
← [SMAPI](../README.md)
|
|
||||||
|
|
||||||
The **mod build package** is an open-source NuGet package which automates the MSBuild configuration
|
|
||||||
for SMAPI mods and related tools. The package is fully compatible with Linux, macOS, and Windows.
|
|
||||||
|
|
||||||
## Contents
|
|
||||||
* [Use](#use)
|
|
||||||
* [Features](#features)
|
|
||||||
* [Configure](#configure)
|
|
||||||
* [Code warnings](#code-warnings)
|
|
||||||
* [FAQs](#faqs)
|
|
||||||
* [How do I set the game path?](#custom-game-path)
|
|
||||||
* [How do I change which files are included in the mod deploy/zip?](#how-do-i-change-which-files-are-included-in-the-mod-deployzip)
|
|
||||||
* [Can I use the package for non-mod projects?](#can-i-use-the-package-for-non-mod-projects)
|
|
||||||
* [For SMAPI developers](#for-smapi-developers)
|
|
||||||
* [Release notes](#release-notes)
|
|
||||||
|
|
||||||
## Use
|
|
||||||
1. Create an empty library project.
|
|
||||||
2. Reference the [`Pathoschild.Stardew.ModBuildConfig` NuGet package](https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig).
|
|
||||||
3. [Write your code](https://stardewvalleywiki.com/Modding:Creating_a_SMAPI_mod).
|
|
||||||
4. Compile on any platform.
|
|
||||||
5. Run the game to play with your mod.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
The package includes several features to simplify mod development (see [_configure_](#configure) to
|
|
||||||
change how these work):
|
|
||||||
|
|
||||||
* **Detect game path:**
|
|
||||||
The package automatically finds your game folder by scanning the default install paths and
|
|
||||||
Windows registry. It adds two MSBuild properties for use in your `.csproj` file if needed:
|
|
||||||
`$(GamePath)` and `$(GameModsPath)`.
|
|
||||||
|
|
||||||
* **Add assembly references:**
|
|
||||||
The package adds assembly references to MonoGame, SMAPI, Stardew Valley, and xTile. It
|
|
||||||
automatically adjusts depending on which OS you're compiling it on. If you use
|
|
||||||
[Harmony](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Harmony), it can optionally add
|
|
||||||
a reference to that too.
|
|
||||||
|
|
||||||
* **Copy files into the `Mods` folder:**
|
|
||||||
The package automatically copies your mod's DLL and PDB files, `manifest.json`, [`i18n`
|
|
||||||
files](https://stardewvalleywiki.com/Modding:Translations) (if any), and the `assets` folder (if
|
|
||||||
any) into the `Mods` folder when you rebuild the code, with a subfolder matching the mod's project
|
|
||||||
name. That lets you try the mod in-game right after building it.
|
|
||||||
|
|
||||||
* **Create release zip:**
|
|
||||||
The package adds a zip file in your project's `bin` folder when you rebuild the code, in the
|
|
||||||
format recommended for uploading to mod sites like Nexus Mods. This includes the same files as
|
|
||||||
the previous feature.
|
|
||||||
|
|
||||||
* **Launch or debug mod:**
|
|
||||||
On Windows only, the package configures Visual Studio so you can launch the game and attach a
|
|
||||||
debugger using _Debug > Start Debugging_ or _Debug > Start Without Debugging_. This lets you [set
|
|
||||||
breakpoints](https://docs.microsoft.com/en-us/visualstudio/debugger/using-breakpoints?view=vs-2019)
|
|
||||||
in your code while the game is running, or [make simple changes to the mod code without needing to
|
|
||||||
restart the game](https://docs.microsoft.com/en-us/visualstudio/debugger/edit-and-continue?view=vs-2019).
|
|
||||||
This is disabled on Linux/macOS due to limitations with the Mono wrapper.
|
|
||||||
|
|
||||||
* **Preconfigure common settings:**
|
|
||||||
The package automatically enables `.pdb` files (so error logs show line numbers to simplify
|
|
||||||
debugging), and enables support for the simplified SDK-style `.csproj` format.
|
|
||||||
|
|
||||||
* **Add code warnings:**
|
|
||||||
The package runs code analysis on your mod and raises warnings for some common errors or
|
|
||||||
pitfalls. See [_code warnings_](#code-warnings) for more info.
|
|
||||||
|
|
||||||
## Configure
|
|
||||||
### How to set options
|
|
||||||
You can configure the package by setting build properties, which are essentially tags like this:
|
|
||||||
```xml
|
|
||||||
<PropertyGroup>
|
|
||||||
<ModFolderName>CustomModName</ModFolderName>
|
|
||||||
<EnableModDeploy>false</EnableModDeploy>
|
|
||||||
</PropertyGroup>
|
|
||||||
```
|
|
||||||
|
|
||||||
There are two places you can put them:
|
|
||||||
|
|
||||||
* **Global properties** apply to every mod project you open on your computer. That's recommended
|
|
||||||
for properties you want to set for all mods (e.g. a custom game path). Here's where to put them:
|
|
||||||
|
|
||||||
1. Open the home folder on your computer (see instructions for
|
|
||||||
[Linux](https://superuser.com/questions/409218/where-is-my-users-home-folder-in-ubuntu),
|
|
||||||
[macOS](https://www.cnet.com/how-to/how-to-find-your-macs-home-folder-and-add-it-to-finder/),
|
|
||||||
or [Windows](https://www.computerhope.com/issues/ch000109.htm)).
|
|
||||||
2. Create a `stardewvalley.targets` file with this content:
|
|
||||||
```xml
|
|
||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
```
|
|
||||||
3. Add the properties between the `<PropertyGroup>` and `</PropertyGroup>`.
|
|
||||||
|
|
||||||
* **Project properties** apply to a specific project. This is mainly useful for mod-specific
|
|
||||||
options like the mod name. Here's where to put them:
|
|
||||||
|
|
||||||
1. Open the folder containing your mod's source code.
|
|
||||||
2. Open the `.csproj` file in a text editor (Notepad is fine).
|
|
||||||
3. Add the properties between the first `<PropertyGroup>` and `</PropertyGroup>` tags you find.
|
|
||||||
|
|
||||||
**Note:** you can't use a property before it's defined. That mainly means that when setting
|
|
||||||
`GameModsPath`, you'll need to either specify `GamePath` manually or put the full path in
|
|
||||||
`GameModsPath`.
|
|
||||||
|
|
||||||
### Available properties
|
|
||||||
These are the options you can set:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Game properties:
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>property</th>
|
|
||||||
<th>effect</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>GamePath</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
The absolute path to the Stardew Valley folder. This is auto-detected, so you usually don't need to
|
|
||||||
change it.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>GameModsPath</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
The absolute path to the folder containing the game's installed mods (defaults to
|
|
||||||
`$(GamePath)/Mods`), used when deploying the mod files.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
</table>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>Mod build properties:
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>property</th>
|
|
||||||
<th>effect</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>EnableHarmony</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Whether to add a reference to [Harmony](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Harmony)
|
|
||||||
(default `false`). This is only needed if you use Harmony.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>EnableModDeploy</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Whether to copy the mod files into your game's `Mods` folder (default `true`).
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>EnableModZip</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Whether to create a release-ready `.zip` file in the mod project's `bin` folder (default `true`).
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>ModFolderName</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
The mod name for its folder under `Mods` and its release zip (defaults to the project name).
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>ModZipPath</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
The folder path where the release zip is created (defaults to the project's `bin` folder).
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>Specialized properties:
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>property</th>
|
|
||||||
<th>effect</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>BundleExtraAssemblies</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
**Most mods should not change this option.**
|
|
||||||
|
|
||||||
By default (when this is _not_ enabled), only the mod files [normally considered part of the
|
|
||||||
mod](#Features) will be added to the release `.zip` and copied into the `Mods` folder (i.e.
|
|
||||||
"deployed"). That includes the assembly files (`*.dll`, `*.pdb`, and `*.xml`) for your mod project,
|
|
||||||
but any other DLLs won't be deployed.
|
|
||||||
|
|
||||||
Enabling this option will add _all_ dependencies to the build output, then deploy _some_ of them
|
|
||||||
depending on the comma-separated value(s) you set:
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>option</th>
|
|
||||||
<th>result</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>ThirdParty</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Assembly files which don't match any other category.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>System</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Assembly files whose names start with `Microsoft.*` or `System.*`.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>Game</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Assembly files which are part of MonoGame, SMAPI, or Stardew Valley.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>All</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Equivalent to `System, Game, ThirdParty`.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
Most mods should omit the option. Some mods may need `ThirdParty` if they bundle third-party DLLs
|
|
||||||
with their mod. The other options are mainly useful for unit tests.
|
|
||||||
|
|
||||||
When enabling this option, you should **manually review which files get deployed** and use the
|
|
||||||
`IgnoreModFilePaths` or `IgnoreModFilePatterns` options to exclude files as needed.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>EnableGameDebugging</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Whether to configure the project so you can launch or debug the game through the _Debug_ menu in
|
|
||||||
Visual Studio (default `true`). There's usually no reason to change this, unless it's a unit test
|
|
||||||
project.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>IgnoreModFilePaths</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
A comma-delimited list of literal file paths to ignore, relative to the mod's `bin` folder. Paths
|
|
||||||
are case-sensitive, but path delimiters are normalized automatically. For example, this ignores a
|
|
||||||
set of tilesheets:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<IgnoreModFilePaths>assets/paths.png, assets/springobjects.png</IgnoreModFilePaths>
|
|
||||||
```
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><code>IgnoreModFilePatterns</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
A comma-delimited list of regex patterns matching files to ignore when deploying or zipping the mod
|
|
||||||
files (default empty). For crossplatform compatibility, you should replace path delimiters with `[/\\]`.
|
|
||||||
|
|
||||||
For example, this excludes all `.txt` and `.pdf` files, as well as the `assets/paths.png` file:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<IgnoreModFilePatterns>\.txt$, \.pdf$, assets[/\\]paths.png</IgnoreModFilePatterns>
|
|
||||||
```
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
## Code warnings
|
|
||||||
### Overview
|
|
||||||
The NuGet package adds code warnings in Visual Studio specific to Stardew Valley. For example:
|
|
||||||
![](screenshots/code-analyzer-example.png)
|
|
||||||
|
|
||||||
You can [hide the warnings](https://visualstudiomagazine.com/articles/2017/09/01/hide-compiler-warnings.aspx)
|
|
||||||
if needed using the warning ID (shown under 'code' in the Error List).
|
|
||||||
|
|
||||||
See below for help with specific warnings.
|
|
||||||
|
|
||||||
### Avoid implicit net field cast
|
|
||||||
Warning text:
|
|
||||||
> This implicitly converts '{{expression}}' from {{net type}} to {{other type}}, but
|
|
||||||
> {{net type}} has unintuitive implicit conversion rules. Consider comparing against the actual
|
|
||||||
> value instead to avoid bugs.
|
|
||||||
|
|
||||||
Stardew Valley uses net types (like `NetBool` and `NetInt`) to handle multiplayer sync. These types
|
|
||||||
can implicitly convert to their equivalent normal values (like `bool x = new NetBool()`), but their
|
|
||||||
conversion rules are unintuitive and error-prone. For example,
|
|
||||||
`item?.category == null && item?.category != null` can both be true at once, and
|
|
||||||
`building.indoors != null` can be true for a null value.
|
|
||||||
|
|
||||||
Suggested fix:
|
|
||||||
* Some net fields have an equivalent non-net property like `monster.Health` (`int`) instead of
|
|
||||||
`monster.health` (`NetInt`). The package will add a separate [AvoidNetField](#avoid-net-field) warning for
|
|
||||||
these. Use the suggested property instead.
|
|
||||||
* For a reference type (i.e. one that can contain `null`), you can use the `.Value` property:
|
|
||||||
```c#
|
|
||||||
if (building.indoors.Value == null)
|
|
||||||
```
|
|
||||||
Or convert the value before comparison:
|
|
||||||
```c#
|
|
||||||
GameLocation indoors = building.indoors;
|
|
||||||
if(indoors == null)
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
* For a value type (i.e. one that can't contain `null`), check if the object is null (if applicable)
|
|
||||||
and compare with `.Value`:
|
|
||||||
```cs
|
|
||||||
if (item != null && item.category.Value == 0)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Avoid net field
|
|
||||||
Warning text:
|
|
||||||
> '{{expression}}' is a {{net type}} field; consider using the {{property name}} property instead.
|
|
||||||
|
|
||||||
Your code accesses a net field, which has some unusual behavior (see [AvoidImplicitNetFieldCast](#avoid-implicit-net-field-cast)).
|
|
||||||
This field has an equivalent non-net property that avoids those issues.
|
|
||||||
|
|
||||||
Suggested fix: access the suggested property name instead.
|
|
||||||
|
|
||||||
### Avoid obsolete field
|
|
||||||
Warning text:
|
|
||||||
> The '{{old field}}' field is obsolete and should be replaced with '{{new field}}'.
|
|
||||||
|
|
||||||
Your code accesses a field which is obsolete or no longer works. Use the suggested field instead.
|
|
||||||
|
|
||||||
### Wrong processor architecture
|
|
||||||
Warning text:
|
|
||||||
> The target platform should be set to 'Any CPU' for compatibility with both 32-bit and 64-bit
|
|
||||||
> versions of Stardew Valley (currently set to '{{current platform}}').
|
|
||||||
|
|
||||||
Mods can be used in either 32-bit or 64-bit mode. Your project's target platform isn't set to the
|
|
||||||
default 'Any CPU', so it won't work in both. You can fix it by [setting the target platform to
|
|
||||||
'Any CPU'](https://docs.microsoft.com/en-ca/visualstudio/ide/how-to-configure-projects-to-target-platforms).
|
|
||||||
|
|
||||||
## FAQs
|
|
||||||
### How do I set the game path?<span id="custom-game-path"></span>
|
|
||||||
The package detects where your game is installed automatically, so you usually don't need to set it
|
|
||||||
manually. If it can't find your game or you have multiple installs, you can specify the path
|
|
||||||
yourself.
|
|
||||||
|
|
||||||
To do that:
|
|
||||||
|
|
||||||
1. Get the full folder path containing the Stardew Valley executable.
|
|
||||||
2. See [_configure_](#configure) to add this property:
|
|
||||||
```xml
|
|
||||||
<PropertyGroup>
|
|
||||||
<GamePath>PATH_HERE</GamePath>
|
|
||||||
</PropertyGroup>
|
|
||||||
```
|
|
||||||
3. Replace `PATH_HERE` with your game's folder path (don't add quotes).
|
|
||||||
|
|
||||||
The configuration will check your custom path first, then fall back to the default paths (so it'll
|
|
||||||
still compile on a different computer).
|
|
||||||
|
|
||||||
### How do I change which files are included in the mod deploy/zip?
|
|
||||||
* For normal files, you can [add/remove them in the build output](https://stackoverflow.com/a/10828462/262123).
|
|
||||||
* For assembly files (`*.dll`, `*.exe`, `*.pdb`, or `*.xml`), see the
|
|
||||||
[`BundleExtraAssemblies` option](#configure).
|
|
||||||
* To exclude a file which the package copies by default, see the [`IgnoreModFilePaths` or
|
|
||||||
`IgnoreModFilePatterns` options](#configure).
|
|
||||||
|
|
||||||
### Can I use the package for non-mod projects?
|
|
||||||
Yep, this works in unit tests and framework projects too. Just disable the mod-related package
|
|
||||||
features (see [_configure_](#configure)):
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<EnableGameDebugging>false</EnableGameDebugging>
|
|
||||||
<EnableModDeploy>false</EnableModDeploy>
|
|
||||||
<EnableModZip>false</EnableModZip>
|
|
||||||
```
|
|
||||||
|
|
||||||
To copy referenced DLLs into your build output for unit tests, add this too:
|
|
||||||
```xml
|
|
||||||
<BundleExtraAssemblies>All</BundleExtraAssemblies>
|
|
||||||
```
|
|
||||||
|
|
||||||
## For SMAPI developers
|
|
||||||
The mod build package consists of three projects:
|
|
||||||
|
|
||||||
project | purpose
|
|
||||||
------------------------------------------------- | ----------------
|
|
||||||
`StardewModdingAPI.ModBuildConfig` | Configures the build (references, deploying the mod files, setting up debugging, etc).
|
|
||||||
`StardewModdingAPI.ModBuildConfig.Analyzer` | Adds C# analyzers which show code warnings in Visual Studio.
|
|
||||||
`StardewModdingAPI.ModBuildConfig.Analyzer.Tests` | Unit tests for the C# analyzers.
|
|
||||||
|
|
||||||
The NuGet package is generated automatically in `StardewModdingAPI.ModBuildConfig`'s `bin` folder
|
|
||||||
when you compile it.
|
|
||||||
|
|
||||||
## Release notes
|
|
||||||
## 4.1.1
|
|
||||||
Released 24 June 2023 for SMAPI 3.13.0 or later.
|
|
||||||
|
|
||||||
* Replaced `.pdb` files with embedded symbols by default. This fixes logged errors not having line numbers on Linux/macOS.
|
|
||||||
|
|
||||||
### 4.1.0
|
|
||||||
Released 08 January 2023 for SMAPI 3.13.0 or later.
|
|
||||||
|
|
||||||
* Added `manifest.json` format validation on build (thanks to tylergibbs2!).
|
|
||||||
* Fixed game DLLs not excluded from the release zip when they're referenced explicitly but `BundleExtraAssemblies` isn't set.
|
|
||||||
|
|
||||||
### 4.0.2
|
|
||||||
Released 09 October 2022 for SMAPI 3.13.0 or later.
|
|
||||||
|
|
||||||
* Switched to the newer crossplatform `portable` debug symbols (thanks to lanturnalis!).
|
|
||||||
* Fixed `BundleExtraAssemblies` option being partly case-sensitive.
|
|
||||||
* Fixed `BundleExtraAssemblies` not applying `All` value to game assemblies.
|
|
||||||
|
|
||||||
### 4.0.1
|
|
||||||
Released 14 April 2022 for SMAPI 3.13.0 or later.
|
|
||||||
|
|
||||||
* Added detection for Xbox app game folders.
|
|
||||||
* Fixed "_conflicts between different versions of Microsoft.Win32.Registry_" warnings in recent SMAPI versions.
|
|
||||||
* Internal refactoring.
|
|
||||||
|
|
||||||
### 4.0.0
|
|
||||||
Released 30 November 2021 for SMAPI 3.13.0 or later.
|
|
||||||
|
|
||||||
* 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.
|
|
||||||
* Removed the `GameExecutableName` and `GameFramework` options (since they now have the same value
|
|
||||||
on all platforms).
|
|
||||||
* Removed the `CopyModReferencesToBuildOutput` option (superseded by `BundleExtraAssemblies`).
|
|
||||||
* Improved analyzer performance by enabling parallel execution.
|
|
||||||
|
|
||||||
**Migration guide for mod authors:**
|
|
||||||
1. See [_migrate to 64-bit_](https://stardewvalleywiki.com/Modding:Migrate_to_64-bit_on_Windows) and
|
|
||||||
[_migrate to Stardew Valley 1.5.5_](https://stardewvalleywiki.com/Modding:Migrate_to_Stardew_Valley_1.5.5).
|
|
||||||
2. Possible changes in your `.csproj` or `.targets` files:
|
|
||||||
* Replace `$(GameExecutableName)` with `Stardew Valley`.
|
|
||||||
* Replace `$(GameFramework)` with `MonoGame` and remove any XNA Framework-specific logic.
|
|
||||||
* Replace `<CopyModReferencesToBuildOutput>true</CopyModReferencesToBuildOutput>` with
|
|
||||||
`<BundleExtraAssemblies>Game</BundleExtraAssemblies>`.
|
|
||||||
* If you need to bundle extra DLLs besides your mod DLL, see the [`BundleExtraAssemblies`
|
|
||||||
documentation](#configure).
|
|
||||||
|
|
||||||
### 3.3.0
|
|
||||||
Released 30 March 2021 for SMAPI 3.0.0 or later.
|
|
||||||
|
|
||||||
* Added a build warning when the mod isn't compiled for `Any CPU`.
|
|
||||||
* Added a `GameFramework` build property set to `MonoGame` or `Xna` based on the platform. This can
|
|
||||||
be overridden to change which framework it references.
|
|
||||||
* Added support for building mods against the 64-bit Linux version of the game on Windows.
|
|
||||||
* The package now suppresses the misleading 'processor architecture mismatch' warnings.
|
|
||||||
|
|
||||||
### 3.2.2
|
|
||||||
Released 23 September 2020 for SMAPI 3.0.0 or later.
|
|
||||||
|
|
||||||
* Reworked and streamlined how the package is compiled.
|
|
||||||
* Added [SMAPI-ModTranslationClassBuilder](https://github.com/Pathoschild/SMAPI-ModTranslationClassBuilder)
|
|
||||||
files to the ignore list.
|
|
||||||
|
|
||||||
### 3.2.1
|
|
||||||
Released 11 September 2020 for SMAPI 3.0.0 or later.
|
|
||||||
|
|
||||||
* Added more detailed logging.
|
|
||||||
* Fixed _path's format is not supported_ error when using default `Mods` path in 3.2.
|
|
||||||
|
|
||||||
### 3.2.0
|
|
||||||
Released 07 September 2020 for SMAPI 3.0.0 or later.
|
|
||||||
|
|
||||||
* Added option to change `Mods` folder path.
|
|
||||||
* Rewrote documentation to make it easier to read.
|
|
||||||
|
|
||||||
### 3.1.0
|
|
||||||
Released 01 February 2020 for SMAPI 3.0.0 or later.
|
|
||||||
|
|
||||||
* Added support for semantic versioning 2.0.
|
|
||||||
* `0Harmony.dll` is now ignored if the mod references Harmony directly (it's bundled with SMAPI).
|
|
||||||
|
|
||||||
### 3.0.0
|
|
||||||
Released 26 November 2019 for SMAPI 3.0.0 or later.
|
|
||||||
|
|
||||||
* Updated for SMAPI 3.0 and Stardew Valley 1.4.
|
|
||||||
* Added automatic support for `assets` folders.
|
|
||||||
* Added `$(GameExecutableName)` MSBuild variable.
|
|
||||||
* Added support for projects using the simplified `.csproj` format.
|
|
||||||
* Added option to disable game debugging config.
|
|
||||||
* Added `.pdb` files to builds by default (to enable line numbers in error stack traces).
|
|
||||||
* Added optional Harmony reference.
|
|
||||||
* Fixed `Newtonsoft.Json.pdb` included in release zips when Json.NET is referenced directly.
|
|
||||||
* Fixed `<IgnoreModFilePatterns>` not working for `i18n` files.
|
|
||||||
* Dropped support for older versions of SMAPI and Visual Studio.
|
|
||||||
* Migrated package icon to NuGet's new format.
|
|
||||||
|
|
||||||
### 2.2.0
|
|
||||||
Released 28 October 2018.
|
|
||||||
|
|
||||||
* Added support for SMAPI 2.8+ (still compatible with earlier versions).
|
|
||||||
* Added default game paths for 32-bit Windows.
|
|
||||||
* Fixed valid manifests marked invalid in some cases.
|
|
||||||
|
|
||||||
### 2.1.0
|
|
||||||
Released 27 July 2018.
|
|
||||||
|
|
||||||
* Added support for Stardew Valley 1.3.
|
|
||||||
* Added support for non-mod projects.
|
|
||||||
* Added C# analyzers to warn about implicit conversions of Netcode fields in Stardew Valley 1.3.
|
|
||||||
* Added option to ignore files by regex pattern.
|
|
||||||
* Added reference to new SMAPI DLL.
|
|
||||||
* Fixed some game paths not detected by NuGet package.
|
|
||||||
|
|
||||||
### 2.0.2
|
|
||||||
Released 01 November 2017.
|
|
||||||
|
|
||||||
* Fixed compatibility issue on Linux.
|
|
||||||
|
|
||||||
### 2.0.1
|
|
||||||
Released 11 October 2017.
|
|
||||||
|
|
||||||
* Fixed mod deploy failing to create subfolders if they don't already exist.
|
|
||||||
|
|
||||||
### 2.0.0
|
|
||||||
Released 11 October 2017.
|
|
||||||
|
|
||||||
* Added: mods are now copied into the `Mods` folder automatically (configurable).
|
|
||||||
* Added: release zips are now created automatically in your build output folder (configurable).
|
|
||||||
* Added: mod deploy and release zips now exclude Json.NET automatically, since it's provided by SMAPI.
|
|
||||||
* Added mod's version to release zip filename.
|
|
||||||
* Improved errors to simplify troubleshooting.
|
|
||||||
* Fixed release zip not having a mod folder.
|
|
||||||
* Fixed release zip failing if mod name contains characters that aren't valid in a filename.
|
|
||||||
|
|
||||||
### 1.7.1
|
|
||||||
Released 28 July 2017.
|
|
||||||
|
|
||||||
* Fixed issue where i18n folders were flattened.
|
|
||||||
* The manifest/i18n files in the project now take precedence over those in the build output if both
|
|
||||||
are present.
|
|
||||||
|
|
||||||
### 1.7.0
|
|
||||||
Released 28 July 2017.
|
|
||||||
|
|
||||||
* Added option to create release zips on build.
|
|
||||||
* Added reference to XNA's XACT library for audio-related mods.
|
|
||||||
|
|
||||||
### 1.6.2
|
|
||||||
Released 10 July 2017.
|
|
||||||
|
|
||||||
* Further improved crossplatform game path detection.
|
|
||||||
* Removed undocumented `GamePlatform` build property.
|
|
||||||
|
|
||||||
### 1.6.1
|
|
||||||
Released 09 July 2017.
|
|
||||||
|
|
||||||
* Improved crossplatform game path detection.
|
|
||||||
|
|
||||||
### 1.6.0
|
|
||||||
Released 05 June 2017.
|
|
||||||
|
|
||||||
* Added support for deploying mod files into `Mods` automatically.
|
|
||||||
* Added a build error if a game folder is found, but doesn't contain Stardew Valley or SMAPI.
|
|
||||||
|
|
||||||
### 1.5.0
|
|
||||||
Released 23 January 2017.
|
|
||||||
|
|
||||||
* Added support for setting a custom game path globally.
|
|
||||||
* Added default GOG path on macOS.
|
|
||||||
|
|
||||||
### 1.4.0
|
|
||||||
Released 11 January 2017.
|
|
||||||
|
|
||||||
* Fixed detection of non-default game paths on 32-bit Windows.
|
|
||||||
* Removed support for SilVerPLuM (discontinued).
|
|
||||||
* Removed support for overriding the target platform (no longer needed since SMAPI crossplatforms
|
|
||||||
mods automatically).
|
|
||||||
|
|
||||||
### 1.3.0
|
|
||||||
Released 31 December 2016.
|
|
||||||
|
|
||||||
* Added support for non-default game paths on Windows.
|
|
||||||
|
|
||||||
### 1.2.0
|
|
||||||
Released 24 October 2016.
|
|
||||||
|
|
||||||
* Exclude game binaries from mod build output.
|
|
||||||
|
|
||||||
### 1.1.0
|
|
||||||
Released 21 October 2016.
|
|
||||||
|
|
||||||
* Added support for overriding the target platform.
|
|
||||||
|
|
||||||
### 1.0.0
|
|
||||||
Released 21 October 2016.
|
|
||||||
|
|
||||||
* Initial release.
|
|
||||||
* Added support for detecting the game path automatically.
|
|
||||||
* Added support for injecting XNA/MonoGame references automatically based on the OS.
|
|
||||||
* Added support for mod builders like SilVerPLuM.
|
|
Before Width: | Height: | Size: 3.4 KiB |
|
@ -1,176 +0,0 @@
|
||||||
← [README](../README.md)
|
|
||||||
|
|
||||||
This file provides more technical documentation about SMAPI. If you only want to use or create
|
|
||||||
mods, this section isn't relevant to you; see the main README to use or create mods.
|
|
||||||
|
|
||||||
This document is about SMAPI itself; see also [mod build package](mod-package.md) and
|
|
||||||
[web services](web.md).
|
|
||||||
|
|
||||||
# Contents
|
|
||||||
* [Customisation](#customisation)
|
|
||||||
* [Configuration file](#configuration-file)
|
|
||||||
* [Command-line arguments](#command-line-arguments)
|
|
||||||
* [Compile flags](#compile-flags)
|
|
||||||
* [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
|
|
||||||
### Configuration file
|
|
||||||
You can customise some SMAPI behaviour by editing the `smapi-internal/config.json` file in your
|
|
||||||
game folder. See documentation in the file for more info.
|
|
||||||
|
|
||||||
### Command-line arguments
|
|
||||||
The SMAPI installer recognises three command-line arguments:
|
|
||||||
|
|
||||||
argument | purpose
|
|
||||||
-------- | -------
|
|
||||||
`--install` | Preselects the install action, skipping the prompt asking what the user wants to do.
|
|
||||||
`--uninstall` | Preselects the uninstall action, skipping the prompt asking what the user wants to do.
|
|
||||||
`--game-path "path"` | Specifies the full path to the folder containing the Stardew Valley executable, skipping automatic detection and any prompt to choose a path. If the path is not valid, the installer displays an error.
|
|
||||||
`--no-prompt` | Don't let the installer wait for user input (e.g. for cases where it's being run by a script). If the installer is unable to continue without user input, it'll fail instead.
|
|
||||||
|
|
||||||
SMAPI itself recognises five arguments, but these are meant for internal use or testing, and might
|
|
||||||
change without warning. **On Linux/macOS**, command-line arguments won't work; see _environment
|
|
||||||
variables_ below instead.
|
|
||||||
|
|
||||||
argument | purpose
|
|
||||||
-------- | -------
|
|
||||||
`--developer-mode`<br />`--developer-mode-off` | Enable or disable features intended for mod developers. Currently this only makes `TRACE`-level messages appear in the console.
|
|
||||||
`--no-terminal` | SMAPI won't log anything to the console. On Linux/macOS only, this will also prevent the launch script from trying to open a terminal window. (Messages will still be written to the log file.)
|
|
||||||
`--use-current-shell` | On Linux/macOS only, the launch script won't try to open a terminal window. All console output will be sent to the shell running the launch script.
|
|
||||||
`--mods-path` | The path to search for mods, if not the standard `Mods` folder. This can be a path relative to the game folder (like `--mods-path "Mods (test)"`) or an absolute path.
|
|
||||||
|
|
||||||
### Environment variables
|
|
||||||
The above SMAPI arguments may not work on Linux/macOS due to the way the game launcher works. You
|
|
||||||
can set temporary environment variables instead. For example:
|
|
||||||
> SMAPI_MODS_PATH="Mods (multiplayer)" /path/to/StardewValley
|
|
||||||
|
|
||||||
environment variable | purpose
|
|
||||||
-------------------- | -------
|
|
||||||
`SMAPI_DEVELOPER_MODE` | Equivalent to `--developer-mode` and `--developer-mode-off` above. The value must be `true` or `false`.
|
|
||||||
`SMAPI_MODS_PATH` | Equivalent to `--mods-path` above.
|
|
||||||
`SMAPI_NO_TERMINAL` | Equivalent to `--no-terminal` above.
|
|
||||||
`SMAPI_USE_CURRENT_SHELL` | Equivalent to `--use-current-shell` above.
|
|
||||||
|
|
||||||
### Compile flags
|
|
||||||
SMAPI uses a small number of conditional compilation constants, which you can set by editing the
|
|
||||||
`<DefineConstants>` element in `SMAPI.csproj`. Supported constants:
|
|
||||||
|
|
||||||
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`.
|
|
||||||
`SMAPI_DEPRECATED` | Whether to include deprecated code in the build.
|
|
||||||
|
|
||||||
## 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. 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.
|
|
||||||
|
|
||||||
Rebuilding the solution in debug mode will copy the SMAPI files into your game folder. Starting
|
|
||||||
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.
|
|
||||||
|
|
||||||
### Custom Harmony build
|
|
||||||
SMAPI uses [a custom build of Harmony 2.2.2](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.
|
|
||||||
|
|
||||||
## 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 platforms, _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
|
|
||||||
sudo tar -xzvf rider-install.tar.gz -C /opt
|
|
||||||
ln -s "/opt/JetBrains Rider-<version>/bin/rider.sh"
|
|
||||||
./rider.sh
|
|
||||||
```
|
|
||||||
3. Clone the SMAPI repo:
|
|
||||||
```sh
|
|
||||||
git clone https://github.com/Pathoschild/SMAPI.git
|
|
||||||
```
|
|
||||||
|
|
||||||
### Launch the game
|
|
||||||
1. Run these commands to start Steam:
|
|
||||||
```sh
|
|
||||||
export TERM=xterm
|
|
||||||
steam
|
|
||||||
```
|
|
||||||
2. Launch the game through the Steam UI.
|
|
||||||
|
|
||||||
### Prepare the release
|
|
||||||
1. Run `build/unix/prepare-install-package.sh VERSION_HERE` to create the release package in the
|
|
||||||
root `bin` folder.
|
|
||||||
|
|
||||||
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`
|
|
||||||
|
|
||||||
### 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/prepare-install-package.ps1 VERSION_HERE` in PowerShell to create the release
|
|
||||||
package folders in the root `bin` folder.
|
|
||||||
|
|
||||||
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. Launch WSL and run this script:
|
|
||||||
```bash
|
|
||||||
# edit to match the build created in steps 1
|
|
||||||
# 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"
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: to prepare a test Windows-only build, you can pass `--windows-only` in the first step and
|
|
||||||
skip the second one.
|
|
||||||
|
|
||||||
## Release notes
|
|
||||||
See [release notes](../release-notes.md).
|
|
|
@ -1,388 +0,0 @@
|
||||||
← [README](../README.md)
|
|
||||||
|
|
||||||
**SMAPI.Web** contains the code for the `smapi.io` website, including the mod compatibility list
|
|
||||||
and update check API.
|
|
||||||
|
|
||||||
## Contents
|
|
||||||
* [Log parser](#log-parser)
|
|
||||||
* [JSON validator](#json-validator)
|
|
||||||
* [Web API](#web-api)
|
|
||||||
* [Short URLs](#short-urls)
|
|
||||||
* [For SMAPI developers](#for-smapi-developers)
|
|
||||||
* [Local development](#local-development)
|
|
||||||
* [Production environment](#production-environment)
|
|
||||||
|
|
||||||
## Log parser
|
|
||||||
The log parser at https://smapi.io/log provides a web UI for uploading, parsing, and sharing SMAPI
|
|
||||||
logs.
|
|
||||||
|
|
||||||
The logs are saved in a compressed form to Amazon Blob storage for 30 days.
|
|
||||||
|
|
||||||
## JSON validator
|
|
||||||
### Overview
|
|
||||||
The JSON validator at https://smapi.io/json provides a web UI for uploading and sharing JSON files,
|
|
||||||
and validating them as plain JSON or against a predefined format like `manifest.json` or Content
|
|
||||||
Patcher's `content.json`.
|
|
||||||
|
|
||||||
The logs are saved in a compressed form to Amazon Blob storage for 30 days.
|
|
||||||
|
|
||||||
### Schema file format
|
|
||||||
Schema files are defined in `wwwroot/schemas` using the [JSON Schema](https://json-schema.org/)
|
|
||||||
format. The JSON validator UI recognises a superset of the standard fields to change output:
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>Documentation URL</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
The root schema may have a `@documentationURL` field, which is a web URL for the user
|
|
||||||
documentation:
|
|
||||||
```js
|
|
||||||
"@documentationUrl": "https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Manifest"
|
|
||||||
```
|
|
||||||
|
|
||||||
If present, this is shown in the JSON validator UI.
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
<dt>Error messages</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
Any part of the schema can define an `@errorMessages` field, which overrides matching schema
|
|
||||||
errors. You can override by error code (recommended), or by error type and a regex pattern matched
|
|
||||||
against the error message (more fragile):
|
|
||||||
|
|
||||||
```js
|
|
||||||
// by error type
|
|
||||||
"pattern": "^[a-zA-Z0-9_.-]+\\.dll$",
|
|
||||||
"@errorMessages": {
|
|
||||||
"pattern": "Invalid value; must be a filename ending with .dll."
|
|
||||||
}
|
|
||||||
```
|
|
||||||
```js
|
|
||||||
// by error type + message pattern
|
|
||||||
"@errorMessages": {
|
|
||||||
"oneOf:valid against no schemas": "Missing required field: EntryDll or ContentPackFor.",
|
|
||||||
"oneOf:valid against more than one schema": "Can't specify both EntryDll or ContentPackFor, they're mutually exclusive."
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Error messages may contain special tokens:
|
|
||||||
|
|
||||||
* The `@value` token is replaced with the error's value field. This is usually (but not always) the
|
|
||||||
original field value.
|
|
||||||
* When an error has child errors, by default they're flattened into one message:
|
|
||||||
```
|
|
||||||
line | field | error
|
|
||||||
---- | ---------- | -------------------------------------------------------------------------
|
|
||||||
4 | Changes[0] | JSON does not match schema from 'then'.
|
|
||||||
| | ==> Changes[0].ToArea.Y: Invalid type. Expected Integer but got String.
|
|
||||||
| | ==> Changes[0].ToArea: Missing required fields: Height.
|
|
||||||
```
|
|
||||||
|
|
||||||
If you set the message for an error to `$transparent`, the parent error is omitted entirely and
|
|
||||||
the child errors are shown instead:
|
|
||||||
```
|
|
||||||
line | field | error
|
|
||||||
---- | ------------------- | ----------------------------------------------
|
|
||||||
8 | Changes[0].ToArea.Y | Invalid type. Expected Integer but got String.
|
|
||||||
8 | Changes[0].ToArea | Missing required fields: Height.
|
|
||||||
```
|
|
||||||
|
|
||||||
The child errors themselves may be marked `$transparent`, etc. If an error has no child errors,
|
|
||||||
this override is ignored.
|
|
||||||
|
|
||||||
Validation errors for `then` blocks are transparent by default, unless overridden.
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
### Using a schema file directly
|
|
||||||
You can reference the validator schemas in your JSON file directly using the `$schema` field, for
|
|
||||||
text editors that support schema validation. For example:
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
"$schema": "https://smapi.io/schemas/manifest.json",
|
|
||||||
"Name": "Some mod",
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Available schemas:
|
|
||||||
|
|
||||||
format | schema URL
|
|
||||||
------ | ----------
|
|
||||||
[SMAPI: `manifest.json`](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Manifest) | https://smapi.io/schemas/manifest.json
|
|
||||||
[SMAPI: translations (`i18n` folder)](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Translation) | https://smapi.io/schemas/i18n.json
|
|
||||||
[Content Patcher: `content.json`](https://github.com/Pathoschild/StardewMods/tree/develop/ContentPatcher#readme) | https://smapi.io/schemas/content-patcher.json
|
|
||||||
|
|
||||||
## Web API
|
|
||||||
### Overview
|
|
||||||
SMAPI provides a web API at `smapi.io/api` for use by SMAPI and external tools. The URL includes a
|
|
||||||
`{version}` token, which is the SMAPI version for backwards compatibility. This API is publicly
|
|
||||||
accessible but not officially released; it may change at any time.
|
|
||||||
|
|
||||||
### `/mods` endpoint
|
|
||||||
The API has one `/mods` endpoint. This crossreferences the mod against a variety of sources (e.g.
|
|
||||||
the wiki, Chucklefish, CurseForge, ModDrop, and Nexus) to provide metadata mainly intended for
|
|
||||||
update checks.
|
|
||||||
|
|
||||||
The API accepts a `POST` request with these fields:
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>field</th>
|
|
||||||
<th>summary</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>mods</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
The mods for which to fetch metadata. Included fields:
|
|
||||||
|
|
||||||
|
|
||||||
field | summary
|
|
||||||
----- | -------
|
|
||||||
`id` | The unique ID in the mod's `manifest.json`. This is used to crossreference with the wiki, and to index mods in the response. If it's unknown (e.g. you just have an update key), you can use a unique fake ID like `FAKE.Nexus.2400`.
|
|
||||||
`updateKeys` | _(optional)_ [Update keys](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Manifest#Update_checks) which specify the mod pages to check, in addition to any mod pages linked to the `ID`.
|
|
||||||
`installedVersion` | _(optional)_ The installed version of the mod. If not specified, the API won't recommend an update.
|
|
||||||
`isBroken` | _(optional)_ Whether SMAPI failed to load the installed version of the mod, e.g. due to incompatibility. If true, the web API will be more permissive when recommending updates (e.g. allowing a stable → prerelease update).
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>apiVersion</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
_(optional)_ The installed version of SMAPI. If not specified, the API won't recommend an update.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>gameVersion</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
_(optional)_ The installed version of Stardew Valley. This may be used to select updates.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>platform</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
_(optional)_ The player's OS (`Android`, `Linux`, `Mac`, or `Windows`). This may be used to select updates.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>includeExtendedMetadata</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
_(optional)_ Whether to include extra metadata that's not needed for SMAPI update checks, but which
|
|
||||||
may be useful to external tools.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
Example request:
|
|
||||||
```js
|
|
||||||
POST https://smapi.io/api/v3.0/mods
|
|
||||||
{
|
|
||||||
"mods": [
|
|
||||||
{
|
|
||||||
"id": "Pathoschild.ContentPatcher",
|
|
||||||
"updateKeys": [ "nexus:1915" ],
|
|
||||||
"installedVersion": "1.9.2",
|
|
||||||
"isBroken": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"apiVersion": "3.0.0",
|
|
||||||
"gameVersion": "1.4.0",
|
|
||||||
"platform": "Windows",
|
|
||||||
"includeExtendedMetadata": true
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Response fields:
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>field</th>
|
|
||||||
<th>summary</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>id</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
The mod ID you specified in the request.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>suggestedUpdate</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
The update version recommended by the web API, if any. This is based on some internal rules (e.g.
|
|
||||||
it won't recommend a prerelease update if the player has a working stable version) and context
|
|
||||||
(e.g. whether the player is in the game beta channel). Choosing an update version yourself isn't
|
|
||||||
recommended, but you can set `includeExtendedMetadata: true` and check the `metadata` field if you
|
|
||||||
really want to do that.
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>errors</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Human-readable errors that occurred fetching the version info (e.g. if a mod page has an invalid
|
|
||||||
version).
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>metadata</code></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
Extra metadata that's not needed for SMAPI update checks but which may be useful to external tools,
|
|
||||||
if you set `includeExtendedMetadata: true` in the request. Included fields:
|
|
||||||
|
|
||||||
field | summary
|
|
||||||
----- | -------
|
|
||||||
`id` | The known `manifest.json` unique IDs for this mod defined on the wiki, if any. That includes historical versions of the mod.
|
|
||||||
`name` | The normalised name for this mod based on the crossreferenced sites.
|
|
||||||
`nexusID` | The mod ID on [Nexus Mods](https://www.nexusmods.com/stardewvalley/), if any.
|
|
||||||
`chucklefishID` | The mod ID in the [Chucklefish mod repo](https://community.playstarbound.com/resources/categories/stardew-valley.22/), if any.
|
|
||||||
`curseForgeID` | The mod project ID on [CurseForge](https://www.curseforge.com/stardewvalley), if any.
|
|
||||||
`curseForgeKey` | The mod key on [CurseForge](https://www.curseforge.com/stardewvalley), if any. This is used in the mod page URL.
|
|
||||||
`modDropID` | The mod ID on [ModDrop](https://www.moddrop.com/stardew-valley), if any.
|
|
||||||
`gitHubRepo` | The GitHub repository containing the mod code, if any. Specified in the `Owner/Repo` form.
|
|
||||||
`customSourceUrl` | The custom URL to the mod code, if any. This is used for mods which aren't stored in a GitHub repo.
|
|
||||||
`customUrl` | The custom URL to the mod page, if any. This is used for mods which aren't stored on one of the standard mod sites covered by the ID fields.
|
|
||||||
`main` | The primary mod version, if any. This depends on the mod site, but it's typically either the version of the mod itself or of its latest non-optional download.
|
|
||||||
`optional` | The latest optional download version, if any.
|
|
||||||
`unofficial` | The version of the unofficial update defined on the wiki for this mod, if any.
|
|
||||||
`unofficialForBeta` | Equivalent to `unofficial`, but for beta versions of SMAPI or Stardew Valley.
|
|
||||||
`hasBetaInfo` | Whether there's an ongoing Stardew Valley or SMAPI beta which may affect update checks.
|
|
||||||
`compatibilityStatus` | The compatibility status for the mod for the stable version of the game, as defined on the wiki, if any. See [possible values](https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityStatus.cs).
|
|
||||||
`compatibilitySummary` | The human-readable summary of the mod's compatibility in HTML format, if any.
|
|
||||||
`brokeIn` | The SMAPI or Stardew Valley version that broke this mod, if any.
|
|
||||||
`betaCompatibilityStatus`<br />`betaCompatibilitySummary`<br />`betaBrokeIn` | Equivalent to the preceding fields, but for beta versions of SMAPI or Stardew Valley.
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
Example response with `includeExtendedMetadata: false`:
|
|
||||||
```js
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": "Pathoschild.ContentPatcher",
|
|
||||||
"suggestedUpdate": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"url": "https://www.nexusmods.com/stardewvalley/mods/1915"
|
|
||||||
},
|
|
||||||
"errors": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
Example response with `includeExtendedMetadata: true`:
|
|
||||||
```js
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": "Pathoschild.ContentPatcher",
|
|
||||||
"suggestedUpdate": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"url": "https://www.nexusmods.com/stardewvalley/mods/1915"
|
|
||||||
},
|
|
||||||
"metadata": {
|
|
||||||
"id": [ "Pathoschild.ContentPatcher" ],
|
|
||||||
"name": "Content Patcher",
|
|
||||||
"nexusID": 1915,
|
|
||||||
"curseForgeID": 309243,
|
|
||||||
"curseForgeKey": "content-patcher",
|
|
||||||
"modDropID": 470174,
|
|
||||||
"gitHubRepo": "Pathoschild/StardewMods",
|
|
||||||
"main": {
|
|
||||||
"version": "1.10",
|
|
||||||
"url": "https://www.nexusmods.com/stardewvalley/mods/1915"
|
|
||||||
},
|
|
||||||
"hasBetaInfo": true,
|
|
||||||
"compatibilityStatus": "Ok",
|
|
||||||
"compatibilitySummary": "✓ use latest version."
|
|
||||||
},
|
|
||||||
"errors": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Short URLs
|
|
||||||
The SMAPI web services provides a few short URLs for convenience:
|
|
||||||
|
|
||||||
short url | → | target page
|
|
||||||
:-------- | - | :----------
|
|
||||||
[smapi.io/3.0](https://smapi.io/3.0) | → | [stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0](https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0)
|
|
||||||
[smapi.io/community](https://smapi.io/community) | → | [stardewvalleywiki.com/Modding:Community](https://stardewvalleywiki.com/Modding:Community)
|
|
||||||
[smapi.io/docs](https://smapi.io/docs) | → | [stardewvalleywiki.com/Modding:Index](https://stardewvalleywiki.com/Modding:Index)
|
|
||||||
[smapi.io/package](https://smapi.io/package) | → | [github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md](https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md)
|
|
||||||
[smapi.io/troubleshoot](https://smapi.io/troubleshoot) | → | [stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting](https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting)
|
|
||||||
[smapi.io/xnb](https://smapi.io/xnb) | → | [stardewvalleywiki.com/Modding:Using_XNB_mods](https://stardewvalleywiki.com/Modding:Using_XNB_mods)
|
|
||||||
|
|
||||||
## For SMAPI developers
|
|
||||||
### Local environment
|
|
||||||
A local environment lets you run a complete copy of the web project (including cache database) on
|
|
||||||
your machine, with no external dependencies aside from the actual mod sites.
|
|
||||||
|
|
||||||
1. Edit `appsettings.Development.json` and set these options:
|
|
||||||
|
|
||||||
property name | description
|
|
||||||
------------- | -----------
|
|
||||||
`NexusApiKey` | [Your Nexus API key](https://www.nexusmods.com/users/myaccount?tab=api#personal_key).
|
|
||||||
|
|
||||||
Optional settings:
|
|
||||||
|
|
||||||
property name | description
|
|
||||||
--------------------------- | -----------
|
|
||||||
`AzureBlobConnectionString` | The connection string for the Azure Blob storage account. Defaults to using the system's temporary file folder if not specified.
|
|
||||||
`GitHubUsername`<br />`GitHubPassword` | The GitHub credentials with which to query GitHub release info. Defaults to anonymous requests if not specified.
|
|
||||||
|
|
||||||
2. Launch `SMAPI.Web` from Visual Studio to run a local version of the site.
|
|
||||||
|
|
||||||
### Production environment
|
|
||||||
A production environment includes the web servers and cache database hosted online for public
|
|
||||||
access.
|
|
||||||
|
|
||||||
This section assumes you're creating a new environment on Azure, but the app isn't tied to any
|
|
||||||
Azure services. If you want to host it on a different site, you'll need to adjust the instructions
|
|
||||||
accordingly.
|
|
||||||
|
|
||||||
Initial setup:
|
|
||||||
|
|
||||||
1. Create an Azure Blob storage account for uploaded files.
|
|
||||||
2. Create an Azure App Services environment running the latest .NET on Linux or Windows.
|
|
||||||
3. Add these application settings in the new App Services environment:
|
|
||||||
|
|
||||||
property name | description
|
|
||||||
------------------------------- | -----------------
|
|
||||||
`ApiClients.AzureBlobConnectionString` | The connection string for the Azure Blob storage account created in step 2.
|
|
||||||
`ApiClients.GitHubUsername`<br />`ApiClients.GitHubPassword` | The login credentials for the GitHub account with which to fetch release info. If these are omitted, GitHub will impose much stricter rate limits.
|
|
||||||
`ApiClients:NexusApiKey` | The [Nexus API authentication key](https://github.com/Pathoschild/FluentNexus#init-a-client).
|
|
||||||
|
|
||||||
Optional settings:
|
|
||||||
|
|
||||||
property name | description
|
|
||||||
------------------------------- | -----------------
|
|
||||||
`BackgroundServices:Enabled` | Set to `true` to enable background processes like fetching data from the wiki, or false to disable them.
|
|
||||||
`Site:BetaEnabled` | Set to `true` to show a separate download button if there's a beta version of SMAPI in its GitHub releases.
|
|
||||||
`Site:BetaBlurb` | If `Site:BetaEnabled` is true and there's a beta version of SMAPI in its GitHub releases, this is shown on the beta download button as explanatory subtext.
|
|
||||||
`Site:SupporterList` | A list of Patreon supports to credit on the download page.
|
|
||||||
|
|
||||||
To deploy updates, just [redeploy the web project from Visual Studio](https://docs.microsoft.com/en-us/visualstudio/deployment/quickstart-deploy-to-azure).
|
|
|
@ -1,19 +0,0 @@
|
||||||
Any raw assets you want to be deployed with your application can be placed in
|
|
||||||
this directory (and child directories) and given a Build Action of "AndroidAsset".
|
|
||||||
|
|
||||||
These files will be deployed with your package and will be accessible using Android's
|
|
||||||
AssetManager, like this:
|
|
||||||
|
|
||||||
public class ReadAsset : Activity
|
|
||||||
{
|
|
||||||
protected override void OnCreate (Bundle bundle)
|
|
||||||
{
|
|
||||||
base.OnCreate (bundle);
|
|
||||||
|
|
||||||
InputStream input = Assets.Open ("my_asset.txt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Additionally, some Android functions will automatically load asset files:
|
|
||||||
|
|
||||||
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
|
|
|
@ -1,110 +0,0 @@
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProductVersion>8.0.30703</ProductVersion>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<ProjectGuid>{45D7D2FB-6B70-45D1-A595-6E289D6A3468}</ProjectGuid>
|
|
||||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<TemplateGuid>{122416d6-6b49-4ee2-a1e8-b825f31c79fe}</TemplateGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>Loader</RootNamespace>
|
|
||||||
<AssemblyName>Loader</AssemblyName>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<AndroidApplication>True</AndroidApplication>
|
|
||||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
|
||||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
|
||||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
|
||||||
<TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
|
|
||||||
<TargetFramework>net5.0-android</TargetFramework>
|
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
|
||||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
|
||||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
|
||||||
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>True</DebugSymbols>
|
|
||||||
<DebugType>portable</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidUseSharedRuntime>true</AndroidUseSharedRuntime>
|
|
||||||
<AndroidLinkMode>None</AndroidLinkMode>
|
|
||||||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
|
||||||
<AndroidManagedSymbols>false</AndroidManagedSymbols>
|
|
||||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
|
|
||||||
<AndroidDexTool>d8</AndroidDexTool>
|
|
||||||
<!-- <AndroidLinkSkip>Mono.Android;MonoGame.Framework;mscorlib;System.Core;System;System.Drawing.Common;System.Numerics;System.Runtime.Serialization;System.Xml;System.Xml.Linq</AndroidLinkSkip>-->
|
|
||||||
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugSymbols>False</DebugSymbols>
|
|
||||||
<DebugType>portable</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidManagedSymbols>false</AndroidManagedSymbols>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
<AndroidLinkMode>None</AndroidLinkMode>
|
|
||||||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
|
||||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
|
|
||||||
<AndroidDexTool>d8</AndroidDexTool>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Resources\Resource.designer.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="packages.config" />
|
|
||||||
<None Include="Resources\AboutResources.txt" />
|
|
||||||
<None Include="Properties\AndroidManifest.xml" />
|
|
||||||
<None Include="Assets\AboutAssets.txt" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\icon.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable\splash.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable\splash_logos_crop.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable\splash_screen.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\colors.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\strings.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\styles.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Mono.Android" />
|
|
||||||
<Reference Include="Mono.Security" />
|
|
||||||
<ProjectReference Include="..\SMAPI\SMAPI.csproj" />
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\mipmap\ic_launcher.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap\ic_launcher_background.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap\ic_launcher_foreground.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap\ic_launcher_round.png" />
|
|
||||||
<AndroidResource Include="Resources\xml\provider_paths.xml">
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</AndroidResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidAsset Include="Assets\Content\**" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
</Project>
|
|
|
@ -1,21 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="156" android:versionName="1.5.6.31" android:installLocation="auto" package="com.zane.stardewvalley2" platformBuildVersionCode="31" platformBuildVersionName="9">
|
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
|
||||||
<application
|
|
||||||
android:label="SMAPI Stardew Valley"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:name="android.app.Application"
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:resizeableActivity="false"
|
|
||||||
android:debuggable="true"
|
|
||||||
android:requestLegacyExternalStorage="true">
|
|
||||||
</application>
|
|
||||||
<uses-permission android:name="com.android.vending.CHECK_LICENSE" />
|
|
||||||
</manifest>
|
|
|
@ -1,44 +0,0 @@
|
||||||
Images, layout descriptions, binary blobs and string dictionaries can be included
|
|
||||||
in your application as resource files. Various Android APIs are designed to
|
|
||||||
operate on the resource IDs instead of dealing with images, strings or binary blobs
|
|
||||||
directly.
|
|
||||||
|
|
||||||
For example, a sample Android app that contains a user interface layout (main.xml),
|
|
||||||
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
|
|
||||||
would keep its resources in the "Resources" directory of the application:
|
|
||||||
|
|
||||||
Resources/
|
|
||||||
drawable/
|
|
||||||
icon.png
|
|
||||||
|
|
||||||
layout/
|
|
||||||
main.xml
|
|
||||||
|
|
||||||
values/
|
|
||||||
strings.xml
|
|
||||||
|
|
||||||
In order to get the build system to recognize Android resources, set the build action to
|
|
||||||
"AndroidResource". The native Android APIs do not operate directly with filenames, but
|
|
||||||
instead operate on resource IDs. When you compile an Android application that uses resources,
|
|
||||||
the build system will package the resources for distribution and generate a class called "R"
|
|
||||||
(this is an Android convention) that contains the tokens for each one of the resources
|
|
||||||
included. For example, for the above Resources layout, this is what the R class would expose:
|
|
||||||
|
|
||||||
public class R {
|
|
||||||
public class drawable {
|
|
||||||
public const int icon = 0x123;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class layout {
|
|
||||||
public const int main = 0x456;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class strings {
|
|
||||||
public const int first_string = 0xabc;
|
|
||||||
public const int second_string = 0xbcd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
|
|
||||||
to reference the layout/main.xml file, or R.strings.first_string to reference the first
|
|
||||||
string in the dictionary file values/strings.xml.
|
|
|
@ -1,175 +0,0 @@
|
||||||
#pragma warning disable 1591
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// <auto-generated>
|
|
||||||
// This code was generated by a tool.
|
|
||||||
//
|
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
|
||||||
// the code is regenerated.
|
|
||||||
// </auto-generated>
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
[assembly: global::Android.Runtime.ResourceDesignerAttribute("Loader.Resource", IsApplication=true)]
|
|
||||||
|
|
||||||
namespace Loader
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "13.2.0.99")]
|
|
||||||
public partial class Resource
|
|
||||||
{
|
|
||||||
|
|
||||||
static Resource()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UpdateIdValues()
|
|
||||||
{
|
|
||||||
global::StardewModdingAPI.Resource.String.app_name = global::Loader.Resource.String.app_name;
|
|
||||||
global::StardewModdingAPI.Resource.String.hello = global::Loader.Resource.String.hello;
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class Attribute
|
|
||||||
{
|
|
||||||
|
|
||||||
static Attribute()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Attribute()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class Color
|
|
||||||
{
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F010000
|
|
||||||
public const int colorAccent = 2130771968;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F010001
|
|
||||||
public const int colorPrimary = 2130771969;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F010002
|
|
||||||
public const int colorPrimaryDark = 2130771970;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F010003
|
|
||||||
public const int ic_launcher_background = 2130771971;
|
|
||||||
|
|
||||||
static Color()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class Drawable
|
|
||||||
{
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F020000
|
|
||||||
public const int icon = 2130837504;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F020001
|
|
||||||
public const int splash = 2130837505;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F020002
|
|
||||||
public const int splash_logos_crop = 2130837506;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F020003
|
|
||||||
public const int splash_screen = 2130837507;
|
|
||||||
|
|
||||||
static Drawable()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Drawable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class Mipmap
|
|
||||||
{
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F030000
|
|
||||||
public const int ic_launcher = 2130903040;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F030001
|
|
||||||
public const int ic_launcher_background = 2130903041;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F030002
|
|
||||||
public const int ic_launcher_foreground = 2130903042;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F030003
|
|
||||||
public const int ic_launcher_round = 2130903043;
|
|
||||||
|
|
||||||
static Mipmap()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Mipmap()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class String
|
|
||||||
{
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F040000
|
|
||||||
public const int action_settings = 2130968576;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F040001
|
|
||||||
public const int app_name = 2130968577;
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F040002
|
|
||||||
public const int hello = 2130968578;
|
|
||||||
|
|
||||||
static String()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class Style
|
|
||||||
{
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F050000
|
|
||||||
public const int Theme_Splash = 2131034112;
|
|
||||||
|
|
||||||
static Style()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Style()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class Xml
|
|
||||||
{
|
|
||||||
|
|
||||||
// aapt resource value: 0x7F060000
|
|
||||||
public const int provider_paths = 2131099648;
|
|
||||||
|
|
||||||
static Xml()
|
|
||||||
{
|
|
||||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Xml()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 1591
|
|
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 14 KiB |
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item>
|
|
||||||
<color android:color="#ffffff" />
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<bitmap android:tileMode="disabled" android:gravity="center" android:src="@drawable/splash_logos_crop"/>
|
|
||||||
</item>
|
|
||||||
</layer-list>
|
|
Before Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 965 B |