Difference between revisions of "Modding:Modder Guide/Game Fundamentals"
Margotbean (talk | contribs) m (Text replacement - "i.e. " to "''i.e.,'' ") |
Pathoschild (talk | contribs) (+ string keys) |
||
Line 143: | Line 143: | ||
: You can test whether your mod accounts for this correctly by setting the zoom to maximum and the UI scale to minimum (''i.e.,'' have them at opposite values) or vice versa; in particular check any logic which handles pixel positions, like menus clicking. | : You can test whether your mod accounts for this correctly by setting the zoom to maximum and the UI scale to minimum (''i.e.,'' have them at opposite values) or vice versa; in particular check any logic which handles pixel positions, like menus clicking. | ||
+ | |||
+ | ==Assets== | ||
+ | ===String keys=== | ||
+ | A ''string key'' uniquely identifies where to find translatable text, in the form <samp>{{t|asset name}}:{{t|key}}</samp>. For example, <code>Game1.content.GetString("Strings\\StringsFromCSFiles:spring")</code> will look for a <samp>spring</samp> key in the <samp>Strings\StringsFromCSFiles</samp> file in the content folder (which contains "spring"). This is commonly used in the game code (via <code>Game1.content.GetString</code>) and in data assets which need translatable text. | ||
==Main classes== | ==Main classes== |
Revision as of 02:52, 20 January 2022
- Get started
- Game fundamentals
- Test & troubleshoot
- Release
- API reference
- Basic SMAPI APIs:
- Advanced SMAPI APIs:
- Specific guides
This page explains some of the Stardew Valley fundamentals that are useful for modders. See also Modding:Common tasks.
Concepts
Tiles
The world is laid out as a grid of tiles. Each tile has an (x, y) coordinate which represents its position on the map, where (0, 0) is the top-left tile. The x value increases towards the right, and y increases downwards. For example:
Positions
The game uses three related coordinate systems:
coordinate system | relative to | notes |
---|---|---|
tile position | top-left corner of the map | measured in tiles; used when placing things on the map (e.g., location.Objects uses tile positions). |
absolute position | top-left corner of the map | measured in pixels; used when more granular measurements are needed (e.g., NPC movement). |
screen position | top-left corner of the visible screen | measured in pixels; used when drawing to the screen. |
Here's how to convert between them:
conversion | formula | ||
---|---|---|---|
absolute | → | screen | x - Game1.viewport.X, y - Game1.viewport.Y
|
absolute | → | tile | x / Game1.tileSize, y / Game1.tileSize
|
screen | → | absolute | x + Game1.viewport.X, y + Game1.viewport.Y
|
screen | → | tile | (x + Game1.viewport.X) / Game1.tileSize, (y + Game1.viewport.Y) / Game1.tileSize
|
tile | → | absolute | x * Game1.tileSize, y * Game1.tileSize
|
tile | → | screen | (x * Game1.tileSize) - Game1.viewport.X, (y * Game1.tileSize) - Game1.viewport.Y
|
Net fields
A 'net type' is any of several classes which Stardew Valley uses to sync data between players, and a 'net field' is any field or property of those types. They're named for the Net
prefix in their type names. Net types can represent simple values like NetBool, or complex values like NetFieldDictionary. The game will regularly collect all the net fields reachable from Game1.netWorldState and sync them with other players. That means that many mod changes will be synchronised automatically in multiplayer.
Although net fields can be implicitly converted to an equivalent value type (like bool x = new NetBool(true)
), their conversion rules are counterintuitive and error-prone (e.g., item?.category == null && item?.category != null
can both be true at once). To avoid bugs, never implicitly cast net fields; access the underlying value directly instead. The build config NuGet package should detect most implicit conversions and show an appropriate build warning.
Here's how to access the data in some common net types:
net type | description |
---|---|
NetBool NetColor NetFloat NetInt NetPoint NetString |
A simple synchronised value. Access the value using field.Value. |
NetCollection<T> NetList<T> NetObjectList<T> |
A list of T values. This implements the standard interfaces like IEnumerable<T> and IList<T>, so you can iterate it directly like foreach (T value in field) .
|
NetLongDictionary<TValue, TNetValue> NetPointDictionary<TValue, TNetValue> NetVector2Dictionary<TValue, TNetValue> |
Maps Long, Point, or Vector2 keys to instances of TValue (the underlying value type) and TNetValue (the synchronised net type). You can iterate key/value pairs like foreach (KeyValuePair<Long, TValue> pair in field.Pairs) (replacing Long with Point or Vector2 if needed).
|
Zoom level
The player can set an in-game zoom level between 75% and 200%, which adjusted the size of all pixels shown on the screen. For example, here's a player with the same window size at different zoom levels:
min zoom level (75%) | max zoom level (200%) |
---|---|
- Effect on SMAPI mods
- In game code, this is represented by the Game1.options.zoomLevel field. Coordinates are generally adjusted for zoom level automatically, so you rarely need to account for this; but you can convert an unadjusted coordinate using
position * (1f / Game1.options.zoomLevel)
if needed.
UI scaling
The player can scale the UI between 75% and 150%, separately from and alongside the zoom level. That adjusts the size of pixels shown on the screen for UI elements only. For example, here's a player with the same window size at different UI scaling levels:
min UI scale (75%) | max UI scale (150%) |
---|---|
- Effect on SMAPI mods
- The game has two distinct scaling modes depending on the context: UI mode and non-UI mode. You can check Game1.uiMode to know which mode is active. You should be careful not to mix UI and non-UI coordinates to avoid tricky calculations; for example, do all your work in one coordinate system and then convert them once.
- A quick reference of common scenarios:
context scaling mode which applies clickable menus UI mode (usually) HUD elements UI mode RenderingActiveMenu
RenderedActiveMenuUI mode Rendering
Rendereddepends on the context; check Game1.uiMode draw method for world objects non-UI mode tile (non-pixel) coordinates not affected by UI scaling
- If you need to draw UI when the game isn't in UI mode, you can explicitly set UI scaling mode:
Game1.game1.InUIMode(() => { // your UI draw code here });
- In UI mode, you should usually replace Game1.viewport with Game1.uiViewport. Don't do this if you'll adjust the positions for UI scaling separately, since double-conversion will give you incorrect results. You can convert between UI and non-UI coordinates using Utility.ModifyCoordinatesForUIScale and Utility.ModifyCoordinatesFromUIScale.
- You can test whether your mod accounts for this correctly by setting the zoom to maximum and the UI scale to minimum (i.e., have them at opposite values) or vice versa; in particular check any logic which handles pixel positions, like menus clicking.
Assets
String keys
A string key uniquely identifies where to find translatable text, in the form <asset name>
:<key>
. For example, Game1.content.GetString("Strings\\StringsFromCSFiles:spring")
will look for a spring key in the Strings\StringsFromCSFiles file in the content folder (which contains "spring"). This is commonly used in the game code (via Game1.content.GetString
) and in data assets which need translatable text.
Main classes
Game1
Game1 is the game's core logic. Most of the game state is tracked through this class. Here are some of the most useful fields:
field | type | purpose |
---|---|---|
Game1.player | Farmer | The current player. |
Game1.currentLocation | GameLocation | The game location containing the current player. For a non-main player, may be null when transitioning between locations. |
Game1.locations | IList<GameLocation> | All locations in the game. For a non-main player, use SMAPI's GetActiveLocations method instead. |
Game1.timeOfDay Game1.dayOfMonth Game1.currentSeason Game1.year |
int int string int |
The current time, day, season, and year. See also SMAPI's date utility. |
Game1.itemsToShip | IList<Item> | Do not use (this is part of the save logic). See Game1.getFarm().getShippingBin(Farmer) instead. |
Game1.activeClickableMenu | IClickableMenu | The modal menu being displayed. Creating an IClickableMenu subclass and assigning an instance to this field will display it. |
GameLocation et al
- GameLocation represents an in-game location players can visit. Each location has a map (the tile layout), objects, trees, characters, etc. Here are some of the most useful fields for any location:
field type purpose Name string The unique name for this location. (This isn't unique for constructed building interiors like cabins; see uniqueName instead.) IsFarm bool Whether this is a farm, where crops can be planted. IsGreenhouse bool Whether this is a greenhouse, where crops can be planted and grown all year. IsOutdoors bool Whether the location is outdoors (as opposed to a greenhouse, building, etc). characters NetCollection of NPC The villagers, pets, horses, and monsters in the location. critters List of Critter The temporary birds, squirrels, or other critters in the location. debris NetCollection of Debris The floating items in the location. farmers FarmerCollection The players in the location. Objects OverlaidDictionary The placed fences, crafting machines, and other objects in the current location. (OverlaidDictionary is basically a NetVector2Dictionary with logic added to show certain quest items over pre-existing objects.) terrainFeatures NetVector2Dictionary of TerrainFeature The trees, fruit trees, tall grass, tilled dirt (including crops), and flooring in the location. For each pair, the key is their tile position and the value is the terrain feature instance. waterTiles bool[,] A multi-dimensional array which indicates whether each tile on the map is a lake/river tile. For example, if (location.waterTiles[10, 20])
checks the tile at position (10, 20). - BuildableGameLocation is a subclass of GameLocation for locations where players can construct buildings. In the vanilla game, only the farm is a buildable location. Here are the most useful fields:
field type purpose buildings NetCollection of Building The buildings in the location. - Farm is a subclass of both GameLocation and BuildableGameLocation for locations where the player can have animals and grow crops. In the vanilla, there's only one farm location (accessed using
Game1.getFarm()
). Here are its most useful properties:field type purpose animals NetLongDictionary of FarmAnimal The farm animals currently in the location. resourceClumps NetCollection of ResourceClump The giant crops, large stumps, boulders, and meteorites in the location. piecesOfHay NetInt The amount of hay stored in silos. shippingBin NetCollection of Item The items in the shipping bin. - There are a number of subclasses for specific location (like AdventureGuild) which have fields useful for specific cases.