Changes

m
→‎Constants: Updated to match SMAPI 4.0.6 Constants Class
Line 5: Line 5:  
==Metadata==
 
==Metadata==
 
===Mod path===
 
===Mod path===
SMAPI APIs use relative paths, so you rarely need the absolute path:
+
Before handling mod folder paths, be aware that:
<source lang="c#">
+
* The '''mod's folder path is not consistent'''. The game is installed to different folders, Nexus mods are often unzipped into a folder like <samp>Mods/Your Mod Name 1.27.5-541-1-27-5-1598664794/YourModFolder</samp> by default, and players can organize their mod folders like <samp>Mods/For single-player/YourModFolder</samp>.
var data = helper.Data.ReadJsonFile<SomeDataModel>("assets/data.json");
+
* Paths are formatted differently on Linux/Mac/Android vs Windows.
</source>
     −
When you do need an absolute path, note that the '''mod's install path is not consistent'''. The game is installed to different paths, Nexus mods are often unzipped into a folder like <tt>Mods/Your Mod Name 1.27.5-541-1-27-5-1598664794/YourModFolder</tt> by default, and players can organize their mod folders like <tt>Mods/For single-player/YourModFolder</tt>. You should use the <code>this.Helper.DirectoryPath</code> to get an absolute path if you need it:
+
You don't need to worry about that when using SMAPI APIs, which take relative paths and automatically fix the format if needed:
<source lang="c#">
+
<syntaxhighlight lang="c#">
string filePath = Path.Combine(this.Helper.DirectoryPath, "assets", "data.json");
+
var data = this.Helper.Data.ReadJsonFile<SomeDataModel>("assets/data.json");
var file = new FileInfo(filePath);
+
</syntaxhighlight>
</source>
     −
See ''[[#Constants|Constants]]'' for other paths.
+
If you really need a full path, you should use <samp>this.Helper.DirectoryPath</samp> and <samp>Path.Combine</samp> to get it:
 +
<syntaxhighlight lang="c#">
 +
string path = Path.Combine(this.Helper.DirectoryPath, "assets", "data.json"); // "assets/data.json" in the current mod's folder
 +
var file = new FileInfo(path);
 +
</syntaxhighlight>
 +
 
 +
See ''[[#Constants|Constants]]'' for other paths like the game folder.
    
===Constants===
 
===Constants===
The <tt>Constants</tt> class provides metadata about SMAPI and the game.
+
The <samp>Constants</samp> class provides metadata about SMAPI and the game.
    
{| class="wikitable"
 
{| class="wikitable"
Line 26: Line 30:  
! meaning
 
! meaning
 
|-
 
|-
| <tt>Constants.ApiVersion</tt>
+
| <samp>Constants.ApiVersion</samp>
 
| The version of the running SMAPI instance.
 
| The version of the running SMAPI instance.
 
|-
 
|-
| <tt>Constants.MinimumGameVersion</tt><br /><tt>Constants.MaximumGameVersion</tt>
+
| <samp>Constants.MinimumGameVersion</samp><br /><samp>Constants.MaximumGameVersion</samp>
 
| The game versions supported by the running SMAPI instance.
 
| The game versions supported by the running SMAPI instance.
 
|-
 
|-
| <tt>Constants.TargetPlatform</tt>
+
| <samp>Constants.TargetPlatform</samp>
| The current operating system (one of <tt>Android</tt>, <tt>Linux</tt>, <tt>Mac</tt>, or <tt>Windows</tt>).
+
| The current operating system (one of <samp>Android</samp>, <samp>Linux</samp>, <samp>Mac</samp>, or <samp>Windows</samp>).
 +
|-
 +
| <samp>Constants.GameFramework</samp>
 +
| The game framework running the game (one of <samp>Xna</samp> or <samp>MonoGame</samp>).
 +
|-
 +
| <samp>Constants.GamePath</samp>
 +
| The absolute path to the <samp>Stardew Valley</samp> folder.
 
|-
 
|-
| <tt>Constants.ExecutionPath</tt>
+
| <samp>Constants.ContentPath</samp>
| The absolute path to the <tt>Stardew Valley</tt> folder.
+
| The absolute path to the game's <samp>Content</samp> folder.
 
|-
 
|-
| <tt>Constants.DataPath</tt>
+
| <samp>Constants.DataPath</samp>
 
| The absolute path to the game's data folder (which contains the [[Saves|save folder]]).
 
| The absolute path to the game's data folder (which contains the [[Saves|save folder]]).
 
|-
 
|-
| <tt>Constants.LogDir</tt>
+
| <samp>Constants.LogDir</samp>
 
| The absolute path to the folder containing the game and SMAPI logs.
 
| The absolute path to the folder containing the game and SMAPI logs.
 
|-
 
|-
| <tt>Constants.SavesPath</tt>
+
| <samp>Constants.SavesPath</samp>
 
| The absolute path to the [[Saves|save folder]].
 
| The absolute path to the [[Saves|save folder]].
 
|-
 
|-
| <tt>Constants.CurrentSavePath</tt>
+
| <samp>Constants.CurrentSavePath</samp>
 
| The absolute path to the current save folder, if a save is loaded.
 
| The absolute path to the current save folder, if a save is loaded.
 
|-
 
|-
| <tt>Constants.SaveFolderName</tt>
+
| <samp>Constants.SaveFolderName</samp>
| The name of the current save folder (like <tt>Name_012345789</tt>), if a save is loaded.
+
| The name of the current save folder (like <samp>Name_012345789</samp>), if a save is loaded.
 
|}
 
|}
    
===Context===
 
===Context===
The <tt>Context</tt> class provides information about the game state and player control:
+
The <samp>Context</samp> class provides information about the game state and player control.
   −
{| class="wikitable"
+
; Game/player state&#58;
 +
: {| class="wikitable"
 
|-
 
|-
 
! value
 
! value
 
! meaning
 
! meaning
 
|-
 
|-
| <tt>Context.IsGameLaunched</tt>
+
| <samp>Context.IsGameLaunched</samp>
 
| Whether the game has been launched and initialised. This becomes true immediately before the first update tick.
 
| Whether the game has been launched and initialised. This becomes true immediately before the first update tick.
 
|-
 
|-
| <tt>Context.IsWorldReady</tt>
+
| <samp>Context.IsWorldReady</samp>
 
| Whether the player has loaded a save and the world has finished initialising. Useful for ignoring events before the save is loaded.
 
| Whether the player has loaded a save and the world has finished initialising. Useful for ignoring events before the save is loaded.
 
|-
 
|-
| <tt>Context.IsPlayerFree</tt>
+
| <samp>Context.IsPlayerFree</samp>
| Whether <tt>Context.IsWorldReady</tt> and the player is free to act on the world (no menu is displayed, no cutscene is in progress, etc).
+
| Whether <samp>Context.IsWorldReady</samp> and the player is free to act on the world (no menu is displayed, no cutscene is in progress, etc).
 
|-
 
|-
| <tt>Context.CanPlayerMove</tt>
+
| <samp>Context.CanPlayerMove</samp>
| Whether <tt>Context.IsPlayerFree</tt> and the player is free to move (e.g. not using a tool).
+
| Whether <samp>Context.IsPlayerFree</samp> and the player is free to move (''e.g.,'' not using a tool).
 
|-
 
|-
| <tt>Context.IsMultiplayer</tt>
+
| <samp>Context.IsInDrawLoop</samp>
| Whether <tt>Context.IsWorldReady</tt>, and the player loaded the save in multiplayer mode (regardless of whether any other players are connected).
+
| Whether the game is currently running the draw loop. This isn't relevant to most mods, since you should use [[Modding:Modder Guide/APIs/Events|display events]] to draw to the screen.
 +
|}
 +
 
 +
; [[Multiplayer]]&#58;
 +
: {| class="wikitable"
 
|-
 
|-
| <tt>Context.IsMainPlayer</tt>
+
! value
| Whether <tt>Context.IsWorldReady</tt>, and the player is the main player. This is always true in single-player, and true when hosting in multiplayer.
+
! meaning
 +
|-
 +
| <samp>Context.IsMultiplayer</samp>
 +
| Whether <samp>Context.IsWorldReady</samp>, and the world was loaded in multiplayer mode (regardless of whether any other players are connected) or is currently in split-screen mode.
 +
|-
 +
| <samp>Context.IsSplitScreen</samp>
 +
| Whether <samp>Context.IsMultiplayer</samp> and the ''current player'' is in split-screen mode. This doesn't apply for remote players.
 +
|-
 +
| <samp>Context.HasRemotePlayers</samp>
 +
| Whether <samp>Context.IsMultiplayer</samp> and any players are connected over the network.
 +
|-
 +
| <samp>Context.IsMainPlayer</samp>
 +
| Whether <samp>Context.IsWorldReady</samp>, and the player is the main player. This is always true in single-player, and true when hosting in multiplayer.
 +
|-
 +
| <samp>Context.IsOnHostComputer</samp>
 +
| Whether the current player is on the host computer. This is true when <samp>Context.IsMainPlayer</samp>, or for farmhands in split-screen mode.
 +
|-
 +
| <samp>Context.ScreenId</samp>
 +
| The unique ID of the current screen in split-screen mode. The main player always has ID 0. A screen is always assigned a new ID when it's opened (so a player who quits and rejoins will get a new screen ID).
 
|}
 
|}
    
==Helpers==
 
==Helpers==
 
===Dates===
 
===Dates===
Use <tt>SDate</tt> for calculating in-game dates. You start by creating a date:
+
Use <samp>SDate</samp> for calculating in-game dates. You start by creating a date:
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
var date = SDate.Now(); // current date
 
var date = SDate.Now(); // current date
 
var date = new SDate(28, "spring"); // date in the current year
 
var date = new SDate(28, "spring"); // date in the current year
 
var date = new SDate(28, "spring", 2); // date in the given year
 
var date = new SDate(28, "spring", 2); // date in the given year
 
var date = SDate.From(Game1.Date); // from a game date
 
var date = SDate.From(Game1.Date); // from a game date
</source>
+
</syntaxhighlight>
    
Then you can calculate offsets from any date:
 
Then you can calculate offsets from any date:
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
// add days
 
// add days
 
new SDate(28, "spring", 1).AddDays(370); // 06 fall in year 4
 
new SDate(28, "spring", 1).AddDays(370); // 06 fall in year 4
Line 98: Line 131:  
// subtract days
 
// subtract days
 
new SDate(01, "spring", 2).AddDays(-1); // 28 winter in year 1
 
new SDate(01, "spring", 2).AddDays(-1); // 28 winter in year 1
</source>
+
</syntaxhighlight>
    
...and compare dates:
 
...and compare dates:
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
var a = new SDate(01, "spring");
 
var a = new SDate(01, "spring");
 
var b = new SDate(02, "spring");
 
var b = new SDate(02, "spring");
 
if (a < b) // true
 
if (a < b) // true
 
   ...
 
   ...
</source>
+
</syntaxhighlight>
    
...and get a translated date string:
 
...and get a translated date string:
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
var date = new SDate(15, "summer");
 
var date = new SDate(15, "summer");
 
string message = $"See you on {date.ToLocaleString(withYear: false)}!"; // See you on Summer 15!
 
string message = $"See you on {date.ToLocaleString(withYear: false)}!"; // See you on Summer 15!
</source>
+
</syntaxhighlight>
   −
Note that <tt>SDate</tt> won't let you create invalid dates:
+
Note that <samp>SDate</samp> won't let you create invalid dates:
<source lang="C#">
+
<syntaxhighlight lang="C#">
 
// ArgumentException: Invalid day '30', must be a value from 1 to 28.
 
// ArgumentException: Invalid day '30', must be a value from 1 to 28.
 
new SDate(30, "spring");
 
new SDate(30, "spring");
Line 121: Line 154:  
// ArithmeticException: Adding -1 days to 01 spring Y1 would result in invalid date 28 winter Y0.
 
// ArithmeticException: Adding -1 days to 01 spring Y1 would result in invalid date 28 winter Y0.
 
new SDate(01, "spring", 1).AddDays(-1);
 
new SDate(01, "spring", 1).AddDays(-1);
</source>
+
</syntaxhighlight>
    
Once created, dates have a few properties you can use:
 
Once created, dates have a few properties you can use:
Line 129: Line 162:  
! meaning
 
! meaning
 
|-
 
|-
| <tt>Day</tt>
+
| <samp>Day</samp>
 
| The day of month.
 
| The day of month.
 
|-
 
|-
| <tt>Season</tt>
+
| <samp>Season</samp>
 
| The normalised season name.
 
| The normalised season name.
 
|-
 
|-
| <tt>SeasonIndex</tt>
+
| <samp>SeasonIndex</samp>
| The zero-based season index recognised by game methods like <tt>Utility.getSeasonNameFromNumber</tt>.
+
| The zero-based season index recognised by game methods like <samp>Utility.getSeasonNameFromNumber</samp>.
 
|-
 
|-
| <tt>Year</tt>
+
| <samp>Year</samp>
 
| The year number.
 
| The year number.
 
|-
 
|-
| <tt>DayOfWeek</tt>
+
| <samp>DayOfWeek</samp>
| The day of week (like <tt>Monday</tt>).
+
| The day of week (like <samp>Monday</samp>).
 
|-
 
|-
| <tt>DaysSinceStart</tt>
+
| <samp>DaysSinceStart</samp>
| The number of days since the first day, inclusively (i.e. 01 spring Y1 = 1).
+
| The number of days since the first day, inclusively (''i.e.,'' 01 spring Y1 = 1).
 
|}
 
|}
    
===File paths===
 
===File paths===
<tt>PathUtilities</tt> provides utility methods for working with file paths and [[Modding:Modder Guide/APIs/Content|asset names]], complementing the <tt>Path</tt> class provided by .NET:
+
<samp>PathUtilities</samp> provides utility methods for working with file paths and [[Modding:Modder Guide/APIs/Content|asset names]], complementing the <samp>Path</samp> class provided by .NET:
    
{| class="wikitable"
 
{| class="wikitable"
Line 159: Line 192:  
| Split a path into its delimited segments, like <code>/usr/bin/example</code> &rarr; <code>usr</code>, <code>bin</code>, and <code>example</code>. For example:
 
| Split a path into its delimited segments, like <code>/usr/bin/example</code> &rarr; <code>usr</code>, <code>bin</code>, and <code>example</code>. For example:
   −
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
string[] segments = PathUtilities.GetSegments(Constants.ExecutionPath);
 
string[] segments = PathUtilities.GetSegments(Constants.ExecutionPath);
</source>
+
</syntaxhighlight>
 
|-
 
|-
 
| <code>IsSafeRelativePath</code>
 
| <code>IsSafeRelativePath</code>
Line 167: Line 200:  
|-
 
|-
 
| <code>IsSlug</code>
 
| <code>IsSlug</code>
| Get whether a string can be used as a 'slug', containing only basic characters that are safe in all contexts (e.g. filenames, URLs, SMAPI IDs, etc).
+
| Get whether a string can be used as a 'slug', containing only basic characters that are safe in all contexts (''e.g.,'' filenames, URLs, SMAPI IDs, etc).
 
|-
 
|-
 
| <code>NormalizePath</code>
 
| <code>NormalizePath</code>
 
| Normalize file paths or asset names to match the format used by the current OS. For example:
 
| Normalize file paths or asset names to match the format used by the current OS. For example:
   −
<source lang="c#">string path = PathUtilities.NormalizePathSeparators(@"Characters\Dialogue//Abigail");
+
<syntaxhighlight lang="c#">string path = PathUtilities.NormalizePathSeparators(@"Characters\Dialogue//Abigail");
 
// Linux/Mac: "Characters/Dialogue/Abigail"
 
// Linux/Mac: "Characters/Dialogue/Abigail"
 
// Windows: "Characters\Dialogue\Abigail"
 
// Windows: "Characters\Dialogue\Abigail"
</source>
+
</syntaxhighlight>
 
|}
 
|}
 +
 +
===Per-screen data===
 +
SMAPI's <code>PerScreen&lt;T&gt;</code> utility manages a separate value for each local screen in split-screen mode. See [[Modding:Modder Guide/APIs/Multiplayer#Per-screen data|<samp>PerScreen&lt;T&gt;</samp> in the multiplayer API]] for details.
    
===Semantic versions===
 
===Semantic versions===
Use <tt>SemanticVersion</tt> to manipulate and compare versions per the [http://semver.org/ Semantic Versioning 2.0 standard]. Example usage:
+
Use <samp>SemanticVersion</samp> to manipulate and compare versions per the [http://semver.org/ Semantic Versioning 2.0 standard]. Example usage:
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
// build version from parts
 
// build version from parts
 
ISemanticVersion version = new SemanticVersion(5, 1, 0, "beta");
 
ISemanticVersion version = new SemanticVersion(5, 1, 0, "beta");
Line 191: Line 227:  
new SemanticVersion("5.10").IsNewerThan("5.10-beta"); // true
 
new SemanticVersion("5.10").IsNewerThan("5.10-beta"); // true
 
new SemanticVersion("5.1").IsBetween("5.0", "5.2"); // true
 
new SemanticVersion("5.1").IsBetween("5.0", "5.2"); // true
</source>
+
</syntaxhighlight>
   −
Note that game versions before 1.2.0 and some mod versions are non-standard (e.g. Stardew Valley 1.11 comes ''before'' 1.2). All SMAPI versions are standard.
+
Note that game versions before 1.2.0 and some mod versions are non-standard (''e.g.,'' Stardew Valley 1.11 comes ''before'' 1.2). All SMAPI versions are standard.
    
==Input==
 
==Input==
SMAPI's <tt>SButton</tt> constants uniquely represent controller, keyboard, and mouse button presses or clicks. See the [[../Input|Input]] page for more info.
+
SMAPI's <samp>SButton</samp> constants uniquely represent controller, keyboard, and mouse button presses or clicks. See the [[../Input|Input]] page for more info.
2

edits