« back to index

Creating a SMAPI mod

Ready to make your own mod? This page will help you create your first mod and use the available APIs and events.

Quick start

The rest of this page will help you create a mod. If you’re experienced enough to skip the tutorial, here’s a quick summary of what this page will walk you through:

  1. Create an empty C# library project.
  2. Target .NET Framework 4.5 (for Linux compatibility).
  3. Reference the Pathoschild.Stardew.ModBuildConfig NuGet package to automatically add the right references depending on the platform the mod is being compiled on.
  4. Create an entry class which subclasses StardewModdingAPI.Mod.
  5. Override the Entry method, and write your code using the SMAPI events and APIs.
  6. Create a manifest.json file which describes your mod for SMAPI.
  7. Create a zip file containing the mod files for release.

Intro

What is SMAPI?

A SMAPI mod uses the SMAPI modding API to extend the game logic. You can run code when something happens (e.g. mouse clicked or menu opened), or periodically (e.g. once per game tick).

SMAPI mods are written in C# using the .NET Framework. Stardew Valley also uses XNA (on Windows) or MonoGame (on Linux and Mac) for the fundamental game logic (drawing to the screen, user input, etc).

Can I make a mod?

The next few sections will walk you through creating a very simple mod. If you follow along, you’ll have created a mod! All that will be left is making it do what you want. :)

What do I need?

Before you start:

Where can I get help?

The Stardew Valley modding community is very welcoming. Feel free come chat on Discord or post in the forums.

How to make a mod

A SMAPI mod is a compiled library (DLL) with an entry method that gets called by SMAPI, so let’s set that up.

Create the project structure

  1. Open Visual Studio or MonoDevelop.
  2. Create a new solution with a library project.
    • In Visual Studio, choose Visual C# » Class Library. (Make sure you choose “Class Library”, not “Class Library (.NET Core)” or “Class Library (Portable)”.)
    • In MonoDevelop, choose Other » .NET » Library.
  3. Change the target framework to .NET 4.5 (for compatibility with Linux).
    • In Visual Studio: right-click on the project, choose Properties, click the Application tab, and change the Target framework dropdown to .NET Framework 4.5.
    • In MonoDevelop: right-click on the project, choose Options, click the Build » General tab, and change the Target framework dropdown to Mono / .NET 4.5.
  4. Delete the Class1.cs or MyClass.cs file.

Configure the build

  1. Reference the Pathoschild.Stardew.ModBuildConfig NuGet package. This will automatically configure your project to load the right modding dependencies for the current platform, so your mod can be built on Linux, Mac, or Windows. It also adds support for debugging the mod in-game.
    • In Visual Studio: click Tools » NuGet Package Manager » Manage NuGet Packages for Solution and search for Pathoschild.Stardew.ModBuildConfig. Select the package named MSBuild config for Stardew Valley mods, check the box next to your project, and click the Install button.
    • In MonoDevelop: click Project » Add NuGet Packages and search for Pathoschild.Stardew.ModBuildConfig. Select the package named MSBuild config for Stardew Valley mods and click Add Package.
  2. (optional) See the package’s Simplify mod development to automatically package your mod into your mod folder and enable debugging while the game is running.

That’s all you need (usually). Try building the project; if you get an error that says “failed to find the game install path automatically”, your game is probably not installed to its default path. You just need to specify where it is:

  1. Open your *.csproj file for editing.
  2. Right under the <Project ...> line, add this (with your install path):

    <PropertyGroup>
       <GamePath>your\path\to\Stardew Valley</GamePath>
    </PropertyGroup>
    

    That will add the path to the places it checks. It it doesn’t exist, it’ll fall back to the default paths, so your mod will still work on other computers (e.g. if someone else recompiles it on a different platform for you).

Add your manifest

The mod manifest tells SMAPI about your mod.

  1. Add a file named manifest.json to your project.
  2. Paste this code into the file (changing the <..> placeholders accordingly):

    {
       "Name": "<your project name>",
       "Author": "<your name>",
       "Version": {
          "MajorVersion": 1,
          "MinorVersion": 0,
          "PatchVersion": 0,
          "Build": ""
       },
       "Description": "<One or two sentences about the mod>",
       "UniqueID": "<your project name>",
       "EntryDll": "<your project name>.dll"
    }
    

    This will listed in the console output when the game is launching.

Write the code

Almost done! Now for the code SMAPI will run.

  1. Add a C# class file called ModEntry.cs to your project.
  2. Put this code in the file (replace <your project name> with the name of your project):

    using System;
    using Microsoft.Xna.Framework;
    using StardewModdingAPI;
    using StardewModdingAPI.Events;
    using StardewValley;
    
    namespace <your project name>
    {
        /// <summary>The mod entry point.</summary>
        public class ModEntry : Mod
        {
            /*********
            ** Public methods
            *********/
            /// <summary>Initialise the mod.</summary>
            /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param>
            public override void Entry(IModHelper helper)
            {
                ControlEvents.KeyPressed += this.ReceiveKeyPress;
            }
    
    
            /*********
            ** Private methods
            *********/
            /// <summary>The method invoked when the player presses a keyboard button.</summary>
            /// <param name="sender">The event sender.</param>
            /// <param name="e">The event data.</param>
            private void ReceiveKeyPress(object sender, EventArgsKeyPressed e)
            {
                this.Monitor.Log($"Player pressed {e.KeyPressed}.");
            }
        }
    }
    

Try your mod

  1. Build the project.
  2. Copy the mod into your game’s Mods folder (only if you didn’t do step 2 of configure the build).
    1. In the game’s Mods directory, add a folder with your mod’s name.
    2. Copy your manifest.json and compiled files into the folder you created.
  3. Run the game through SMAPI.

The mod so far will just send a message to the console window whenever you press a key in the game:

example log output

If that didn’t work, something went wrong. Try reviewing the above instructions, or ask for help. :)

Mod APIs

Now that you have a basic mod, here are the SMAPI features you can use to do more.

Events

SMAPI publishes several C# events that tell you when something happens. For example, if you want to do something after the player loads their save, you can add this to your Entry method:

PlayerEvents.LoadedGame += this.ReceiveLoadedGame;

Then declare a method like this. (The EventArgs e argument will often provide more details about what happened, if there are any.)

/// <summmary>The event handler called after the player loads their save.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
public void ReceiveLoadedGame(object sender, EventArgs e)
{
   this.Monitor.Log("The player loaded their game! This is a good time to do things.");
}

Here are the available events:

Configuration

You can let users configure your mod through a config.json file. SMAPI will automatically create the file and take care of reading, normalising, and updating it.

Here’s the simplest way to use config.json:

  1. Create your model. This is just a class with properties for the config options you want, and it can contain almost anything from a few boolean fields to a complex object graph. (You should try to keep it simple for your users, though.)

    You can set defaults directly:

    class ModConfig
    {
       public bool ExampleBoolean { get; set; } = true;
       public float ExampleFloat { get; set; } = 0.5;
    }
    

    …or with a constructor:

    class ModConfig
    {
       public bool ExampleBoolean { get; set; }
       public float ExampleFloat { get; set; }
    
       public ModConfig()
       {
          this.ExampleBoolean = true;
          this.ExampleFloat = 0.5;
       }
    }
    
  2. In your ModEntry::Entry method, add this line to read the config options:

    ModConfig config = helper.ReadConfig<ModConfig>();
    

That’s it! When the player launches the game, SMAPI will create the config.json file automatically if it doesn’t exist yet, using the default config options you provided in your model.

If you need to edit and save the config, you can use helper.SaveConfig(config). You can access the helper in other methods using this.Helper.

For more advanced config and JSON scenarios, see advanced configuration which covers…

Logging

Your mod can write messages to the console window and log file using the monitor. For example, this code:

this.Monitor.Log("a trace message", LogLevel.Trace);
this.Monitor.Log("a debug message", LogLevel.Debug);
this.Monitor.Log("an info message", LogLevel.Info);
this.Monitor.Log("a warning message", LogLevel.Warn);
this.Monitor.Log("an error message", LogLevel.Error);

will log something like this:

[18:00:00 TRACE Mod Name] a trace message
[18:00:00 DEBUG Mod Name] a debug message
[18:00:00 INFO  Mod Name] an info message
[18:00:00 WARN  Mod Name] a warning message
[18:00:00 ERROR Mod Name] an error message

Note that LogLevel.Trace messages won’t appear in the console window by default, they’ll only be written to the log file. Trace messages are for troubleshooting details that are useful when someone sends you their error log, but which the player normally doesn’t need to see. (You can see trace messages in the console if you install the “SMAPI for developers” version.)

Reflection

SMAPI provides an API for robustly accessing the game’s private fields or methods. You can use it from helper.Reflection in your entry method, or this.Helper.Reflection elsewhere in your entry class. It consists of three methods:

Here are a few examples of what this lets you do:

// did you pet your pet today?
bool wasPet = reflection.GetPrivateValue<bool>(pet, "wasPetToday");

// what is the spirit forecast today?
string forecast = reflection
   .GetPrivateMethod(new TV(), "getFortuneForecast")
   .Invoke<string>();

// randomise the mines
if(Game1.currentLocation is MineShaft)
   reflection.GetPrivateField<Random>(Game1.currentLocation, "mineRandom").SetValue(new Random());

This works with static or instance fields/methods, caches the reflection to improve performance, and will throw useful errors automatically when reflection fails.

If you need to do more, you can also switch to C#’s underlying reflection API:

FieldInfo field = reflection.GetPrivateField<string>().FieldInfo;
MethodInfo method = reflection.GetPrivateMethod().MethodInfo;

Release your mod

Ready to share your mod with the world?

Let’s say you created a mod named Pineapples Everywhere which turns all NPCs into pineapples; here’s how you would release it for others to use.

Share your mod

  1. Copy your manifest.json and compiled files into a folder matching your mod’s name (like PineapplesEverywhere). A few tips:
    • Only use letters in the folder name (no spaces or symbols) to simplify troubleshooting later.
    • Add your default config.json if you have settings, so users can edit it before first run.
    • Include the compiled *.pdb file, so error messages include line numbers.
  2. Create a zip archive with your mod’s name, version, and platform.

Your mod structure should look something like this:

PineapplesEverywhere-1.0-Windows.zip
   PineapplesEverywhere/
      PineapplesEverywhere.dll
      PineapplesEverywhere.pdb
      config.json
      manifest.json

The best places to share your mod are Nexus Mods and the official modding forums.

Release on multiple platforms

Want to share your mod on Linux, Mac, and Windows? See crossplatforming a SMAPI mod.

Decompile the game code

When you start working on more complex mods, you may need to look at how the game code works.

Here’s how to decompile the game code so you can look at it:

  1. Open StardewValley.exe in dotPeek.
  2. Right-click on Stardew Valley and choose Export to Project. Accept the default options to create a decompiled project you can open in Visual Studio. (Note that the decompiled code will not be functional due to limitations of the decompiler, but you’ll be able to read the game code.)

Here’s how to unpack the XNB data files:

  1. Download the Easy XNB Pack/UnPack Toolkit.
  2. Copy the entire Stardew Valley\Content game folder into XNB-Mod-Toolkit\Packed.
  3. Run XNB-Mod-Toolkit\UNPACK FILES.bat to unpack the files into XNB-Mod-Toolkit\Unpacked.

See also

If you read the entire guide, congratulations! If you’d like to read even more documentation, go back to the index and look at the ‘Advanced topics’ list. These cover much more specialised topics, like how to parse weather data.