Difference between revisions of "Modding:Modder Guide/Get Started"

From Stardew Valley Wiki
Jump to navigation Jump to search
(add footer nav links)
(merge content from Modding:Modder Guide/Tutorial Mod (main author is Pathoschild, with contributions from Cheesysteak, Hawkfalcon, and Nobbele))
Line 50: Line 50:
  
 
If you're not familiar with Visual Studio 2017 (on Windows/Mac) or MonoDevelop (on Linux), [[Modding:IDE reference]] explains how to do the important stuff you need for this guide.
 
If you're not familiar with Visual Studio 2017 (on Windows/Mac) or MonoDevelop (on Linux), [[Modding:IDE reference]] explains how to do the important stuff you need for this guide.
 +
 +
==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:
 +
 +
# Create an empty C# class library project.
 +
# Target .NET Framework 4.5, 4.5.1, or 4.5.2 for best compatibility.
 +
# Reference the [https://github.com/Pathoschild/Stardew.ModBuildConfig <tt>Pathoschild.Stardew.ModBuildConfig</tt> NuGet package] to automatically add the right references depending on the platform the mod is being compiled on.
 +
# Create a <tt>ModEntry</tt> class which subclasses <tt>StardewModdingAPI.Mod</tt>.
 +
# Override the <tt>Entry</tt> method, and write your code using the [[#Mod APIs|SMAPI events and APIs]].
 +
# Create a [[#Add your manifest|<tt>manifest.json</tt> file]] which describes your mod for SMAPI.
 +
# Create [[#Release your mod|a zip file containing the mod files]] for release.
 +
 +
==Create a basic mod==
 +
===Create the project===
 +
A SMAPI mod is a compiled library (DLL) with an entry method that gets called by SMAPI, so let's set that up.
 +
 +
# Open Visual Studio 2017 or MonoDevelop.
 +
# Create a solution with a .NET Framework class library project (see [[Modding:IDE reference#create-project|how to create a project]]). '''Make sure you choose .NET Framework, not .NET Core or .NET Standard.'''
 +
# Change the target framework to .NET Framework 4.5, 4.5.1, or 4.5.2 for best compatibility (see [[Modding:IDE reference#set-target-framework|how to change target framework]]).
 +
# Reference the [https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig <tt>Pathoschild.Stardew.ModBuildConfig</tt> NuGet package] (see [[Modding:IDE reference#add-nuget|how to add the package]]).
 +
# Restart Visual Studio/MonoDevelop after installing the package.
 +
 +
===Add the code===
 +
Next let's add some code SMAPI will run.
 +
 +
<ol>
 +
<li>Delete the <tt>Class1.cs</tt> or <tt>MyClass.cs</tt> file (see [[Modding:IDE reference#delete-file|how to delete a file]]).</li>
 +
<li>Add a C# class file called <tt>ModEntry.cs</tt> to your project (see [[Modding:IDE reference#Add a file|how to add a file]]).</li>
 +
<li>Put this code in the file (replace <tt>YourProjectName</tt> with the name of your project):
 +
<source lang="c#">
 +
using System;
 +
using Microsoft.Xna.Framework;
 +
using StardewModdingAPI;
 +
using StardewModdingAPI.Events;
 +
using StardewModdingAPI.Utilities;
 +
using StardewValley;
 +
 +
namespace YourProjectName
 +
{
 +
    /// <summary>The mod entry point.</summary>
 +
    public class ModEntry : Mod
 +
    {
 +
        /*********
 +
        ** Public methods
 +
        *********/
 +
        /// <summary>The mod entry point, called after the mod is first loaded.</summary>
 +
        /// <param name="helper">Provides simplified APIs for writing mods.</param>
 +
        public override void Entry(IModHelper helper)
 +
        {
 +
            InputEvents.ButtonPressed += this.InputEvents_ButtonPressed;
 +
        }
 +
 +
 +
        /*********
 +
        ** Private methods
 +
        *********/
 +
        /// <summary>The method invoked when the player presses a controller, keyboard, or mouse button.</summary>
 +
        /// <param name="sender">The event sender.</param>
 +
        /// <param name="e">The event data.</param>
 +
        private void InputEvents_ButtonPressed(object sender, EventArgsInput e)
 +
        {
 +
            // ignore if player hasn't loaded a save yet
 +
            if (!Context.IsWorldReady)
 +
                return;
 +
 +
            // print button presses to the console window
 +
            this.Monitor.Log($"{Game1.player.Name} pressed {e.Button}.");
 +
        }
 +
    }
 +
}
 +
</source></li>
 +
</ol>
 +
 +
Here's a breakdown of what that code is doing:
 +
 +
# <code>using X;</code> (see [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive using directive]) makes classes in that namespace available in your code.
 +
# <code>namespace YourProjectName</code> (see [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/namespace namespace keyword]) defines the scope for your mod code. Don't worry about this when you're starting out, Visual Studio or MonoDevelop will add it automatically when you add a file.
 +
# <code>public class ModEntry : Mod</code> (see [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/class class keyword]) creates your mod's main class, and subclasses SMAPI's <tt>Mod</tt> class. SMAPI will detect your <tt>Mod</tt> subclass automatically, and <tt>Mod</tt> gives you access to SMAPI's APIs.
 +
# <code>public override void Entry(IModHelper helper)</code> is the method SMAPI will call when your mod is loaded into the game. The <code>helper</code> provides convenient access to many of SMAPI's APIs.
 +
# <code>InputEvents.ButtonPressed += this.InputEvents_ButtonPressed;</code> adds an 'event handler' (i.e. a method to call) when the button-pressed event happens. In other words, when a button is pressed (the <tt>InputEvents.ButtonPressed</tt> event), SMAPI will call your <tt>this.InputEvents_ButtonPressed</tt> method. See [[Modding:SMAPI APIs#Events]] for more info.
 +
 +
===Add your manifest===
 +
The mod manifest tells SMAPI about your mod.
 +
 +
<ol>
 +
<li>Add a file named <tt>manifest.json</tt> to your project.</li>
 +
<li>Paste this code into the file (replacing the <tt>&lt;...&gt;</tt> placeholders):
 +
<source lang="json">
 +
{
 +
  "Name": "<your project name>",
 +
  "Author": "<your name>",
 +
  "Version": "1.0.0",
 +
  "Description": "<One or two sentences about the mod>",
 +
  "UniqueID": "<your name>.<your project name>",
 +
  "EntryDll": "<your project name>.dll",
 +
  "MinimumApiVersion": "2.0",
 +
  "UpdateKeys": []
 +
}
 +
</source></li>
 +
</ol>
 +
 +
This will be listed in the console output when the game is launching. For more info, see the [[Modding:SMAPI APIs#Manifest|manifest docs]].
 +
 +
===Try your mod===
 +
# Build the project.<br /><small>If you did the ''[[#Create the project|create the project]]'' steps correctly, this will automatically add your mod to the game's <tt>Mods</tt> folder.</small>
 +
# 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.
 +
 +
===Troubleshooting===
 +
If the tutorial mod doesn't work...
 +
 +
# Review the above steps to make sure you didn't skip something.
 +
# Check for error messages which may explain why it's not working:
 +
#* In Visual Studio, click ''Build > Rebuild Solution'' and check the ''Output'' pane or ''Error'' list.
 +
#* In MonoDevelop, click ''Build > Rebuild All'' and wait until it's done. Then click the "Build: XX errors, XX warnings" bar at the top, and check the ''XX Errors'' and ''Build Output'' tabs.
 +
# If all else fails, come ask for help in the [[Modding:Community#Discord|#modding in the Stardew Valley Discord]]. :)
 +
 +
==Going further==
 +
===SMAPI APIs===
 +
SMAPI provides a set of APIs you can use to do more. See [[Modding:SMAPI APIs]] for more info.
 +
 +
===Crossplatform support===
 +
SMAPI will automatically adjust your mod so it works on Linux, Mac, and Windows. However, there are a few things you should do to avoid problems:
 +
 +
<ol>
 +
<li>Use the [https://github.com/Pathoschild/Stardew.ModBuildConfig#readme crossplatform build config] package to automatically set up your project references. This makes crossplatform compatibility easier and lets your code compile on any platform. (If you followed the above guide, you already have this.)</li>
 +
 +
<li>Use <tt>Path.Combine</tt> to build file paths, don't hardcode path separators since they won't work on all platforms.
 +
 +
<source lang="c#">
 +
// ✘ Don't do this! It will crash on Linux/Mac.
 +
string path = Helper.DirectoryPath + "\assets\asset.xnb";
 +
 +
// ✓ This is OK
 +
string path = Path.Combine(Helper.DirectoryPath, "assets", "asset.xnb");
 +
</source></li>
 +
 +
<li>Use <tt>Helper.DirectoryPath</tt>, don't try to determine the mod path yourself.
 +
 +
<source lang="c#">
 +
// ✘ Don't do this! It will crash if SMAPI rewrites the assembly (e.g. to update or crossplatform it).
 +
string modFolder = Assembly.GetCallingAssembly().Location;
 +
 +
// ✓ This is OK
 +
string modFolder = Helper.DirectoryPath;
 +
</source></li>
 +
</ol>
 +
 +
===Decompile the game code===
 +
When you start working on more complex mods, you may need to look at how the game code works.
 +
 +
To decompile the game code so you can read it (though it won't be fully functional due to decompiler limitations):
 +
* On Windows:
 +
*# Open <tt>StardewValley.exe</tt> in [https://www.jetbrains.com/decompiler/ dotPeek].
 +
*# 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.
 +
* On Linux/Mac:
 +
*# Open <tt>StardewValley.exe</tt> in MonoDevelop through ''File &gt; Open''.
 +
*# Change ''Language'' from ''Summary'' to ''C#''.
 +
 +
To unpack the XNB data/image files, see [[Modding:Editing XNB files]].
  
 
{{modding guide footer
 
{{modding guide footer
 
  |prev =  
 
  |prev =  
  |next = [[Modding:Modder Guide/Tutorial Mod|Creating a Basic Mod]]
+
  |next = [[Modding:Modder Guide/Testing and Releasing|Testing and Releasing]]
 
}}
 
}}

Revision as of 14:56, 3 September 2018

Modding:Modder Guide/Get Started/header

Do you want to create SMAPI mods for Stardew Valley? This guide is for you! For using mods, see Modding:Player Guide.

Intro

What is a SMAPI mod?

A SMAPI mod uses the SMAPI modding API to extend the game logic. The mod can respond when something happens in the game (like when an object is placed in the world), run code periodically (like once per update tick), change the game's assets and data, etc. SMAPI mods are written in C# using the .NET Framework, and Stardew Valley uses XNA/MonoGame for the game logic (drawing to the screen, user input, etc).

Why do mods use SMAPI?

SMAPI does a lot for you! For example, SMAPI will...

  1. Load your mod into the game. Code mods aren't possible without SMAPI to load them.
  2. Provide APIs and events which let you interact with the game in ways you otherwise couldn't. There are simplified APIs for game asset/data changes, player configuration, translation, reflection, etc. These are covered later in the guide.
  3. Rewrite your mod for crossplatform compatibility when it's loaded. That lets you write mod code without worrying about the differences between the Linux/Mac/Windows versions of the game.
  4. Rewrite your mod to update it. SMAPI detects and fixes mod code broken by a game update in common cases.
  5. Intercept errors. If your mod crashes or causes an error, SMAPI will intercept the error, show the error details in the console window, and in most cases automatically recovers the game. This means your mod won't accidentally crash the game, and makes it much easier to troubleshoot errors.
  6. Provide update checks. SMAPI automatically alerts players when a new version of your mod is available.
  7. Provide compatibility checks. SMAPI automatically detects when your mod is incompatible and disables it before it causes problems, so players aren't left with broken games.

Can I make a mod?

Yes! This guide will help you create a simple mod step-by-step. If you follow along, you'll have created a mod! Then you'll just need to make it do what you want.

If you're new to programming: many mod developers start with little or no programming experience. You can certainly learn along the way if you're determined, but you should be prepared for a steep learning curve. Don't be too ambitious at first; it's better to start with a small mod when you're figuring it out. It's easy to become overwhelmed at first and give up. The modding community is very welcoming, so don't be afraid to ask questions!

If you already have programming experience, you should be fine. Programming experience in C# or Java will make things easier, but it isn't critical. If you're unfamiliar with C#, you can skim through the Learning C# references below to fill in any gaps.

Can I make a mod without SMAPI?

Yep. Many SMAPI mods support 'content packs', which let you provide JSON text files, images, etc which they use. For example, you can use Content Patcher to edit the game's images and data with zero programming needed. The rest of this guide is about creating a new SMAPI mod; for content packs, see the documentation for the mod that'll read it.

Where can I get help?

The Stardew Valley modding community is very welcoming. Feel free to ask for help in #modding on the Stardew Valley Discord.

Getting started

Learning C#

Since mods are written in C#, it's a good idea to get acquainted with it first. You don't need to memorise everything, but a grasp of the basics (like fields, methods, variables, and classes) will make everything else much easier.

Some useful resources:

Requirements

Before you start:

  1. Read the Player Guide. The rest of this guide assumes you're already familiar with using mods.
  2. Install Stardew Valley.
  3. Install SMAPI.
  4. Install the IDE (integrated development environment).

If you're not familiar with Visual Studio 2017 (on Windows/Mac) or MonoDevelop (on Linux), Modding:IDE reference explains how to do the important stuff you need for this guide.

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# class library project.
  2. Target .NET Framework 4.5, 4.5.1, or 4.5.2 for best 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 a ModEntry 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.

Create a basic mod

Create the project

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

  1. Open Visual Studio 2017 or MonoDevelop.
  2. Create a solution with a .NET Framework class library project (see how to create a project). Make sure you choose .NET Framework, not .NET Core or .NET Standard.
  3. Change the target framework to .NET Framework 4.5, 4.5.1, or 4.5.2 for best compatibility (see how to change target framework).
  4. Reference the Pathoschild.Stardew.ModBuildConfig NuGet package (see how to add the package).
  5. Restart Visual Studio/MonoDevelop after installing the package.

Add the code

Next let's add some code SMAPI will run.

  1. Delete the Class1.cs or MyClass.cs file (see how to delete a file).
  2. Add a C# class file called ModEntry.cs to your project (see how to add a file).
  3. Put this code in the file (replace YourProjectName with the name of your project):
    using System;
    using Microsoft.Xna.Framework;
    using StardewModdingAPI;
    using StardewModdingAPI.Events;
    using StardewModdingAPI.Utilities;
    using StardewValley;
    
    namespace YourProjectName
    {
        /// <summary>The mod entry point.</summary>
        public class ModEntry : Mod
        {
            /*********
            ** Public methods
            *********/
            /// <summary>The mod entry point, called after the mod is first loaded.</summary>
            /// <param name="helper">Provides simplified APIs for writing mods.</param>
            public override void Entry(IModHelper helper)
            {
                InputEvents.ButtonPressed += this.InputEvents_ButtonPressed;
            }
    
    
            /*********
            ** Private methods
            *********/
            /// <summary>The method invoked when the player presses a controller, keyboard, or mouse button.</summary>
            /// <param name="sender">The event sender.</param>
            /// <param name="e">The event data.</param>
            private void InputEvents_ButtonPressed(object sender, EventArgsInput e)
            {
                // ignore if player hasn't loaded a save yet
                if (!Context.IsWorldReady)
                    return;
    
                // print button presses to the console window
                this.Monitor.Log($"{Game1.player.Name} pressed {e.Button}.");
            }
        }
    }
    

Here's a breakdown of what that code is doing:

  1. using X; (see using directive) makes classes in that namespace available in your code.
  2. namespace YourProjectName (see namespace keyword) defines the scope for your mod code. Don't worry about this when you're starting out, Visual Studio or MonoDevelop will add it automatically when you add a file.
  3. public class ModEntry : Mod (see class keyword) creates your mod's main class, and subclasses SMAPI's Mod class. SMAPI will detect your Mod subclass automatically, and Mod gives you access to SMAPI's APIs.
  4. public override void Entry(IModHelper helper) is the method SMAPI will call when your mod is loaded into the game. The helper provides convenient access to many of SMAPI's APIs.
  5. InputEvents.ButtonPressed += this.InputEvents_ButtonPressed; adds an 'event handler' (i.e. a method to call) when the button-pressed event happens. In other words, when a button is pressed (the InputEvents.ButtonPressed event), SMAPI will call your this.InputEvents_ButtonPressed method. See Modding:SMAPI APIs#Events for more info.

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 (replacing the <...> placeholders):
    {
       "Name": "<your project name>",
       "Author": "<your name>",
       "Version": "1.0.0",
       "Description": "<One or two sentences about the mod>",
       "UniqueID": "<your name>.<your project name>",
       "EntryDll": "<your project name>.dll",
       "MinimumApiVersion": "2.0",
       "UpdateKeys": []
    }
    

This will be listed in the console output when the game is launching. For more info, see the manifest docs.

Try your mod

  1. Build the project.
    If you did the create the project steps correctly, this will automatically add your mod to the game's Mods folder.
  2. 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.

Troubleshooting

If the tutorial mod doesn't work...

  1. Review the above steps to make sure you didn't skip something.
  2. Check for error messages which may explain why it's not working:
    • In Visual Studio, click Build > Rebuild Solution and check the Output pane or Error list.
    • In MonoDevelop, click Build > Rebuild All and wait until it's done. Then click the "Build: XX errors, XX warnings" bar at the top, and check the XX Errors and Build Output tabs.
  3. If all else fails, come ask for help in the #modding in the Stardew Valley Discord. :)

Going further

SMAPI APIs

SMAPI provides a set of APIs you can use to do more. See Modding:SMAPI APIs for more info.

Crossplatform support

SMAPI will automatically adjust your mod so it works on Linux, Mac, and Windows. However, there are a few things you should do to avoid problems:

  1. Use the crossplatform build config package to automatically set up your project references. This makes crossplatform compatibility easier and lets your code compile on any platform. (If you followed the above guide, you already have this.)
  2. Use Path.Combine to build file paths, don't hardcode path separators since they won't work on all platforms.
    // ✘ Don't do this! It will crash on Linux/Mac.
    string path = Helper.DirectoryPath + "\assets\asset.xnb";
    
    // ✓ This is OK
    string path = Path.Combine(Helper.DirectoryPath, "assets", "asset.xnb");
    
  3. Use Helper.DirectoryPath, don't try to determine the mod path yourself.
    // ✘ Don't do this! It will crash if SMAPI rewrites the assembly (e.g. to update or crossplatform it).
    string modFolder = Assembly.GetCallingAssembly().Location;
    
    // ✓ This is OK
    string modFolder = Helper.DirectoryPath;
    

Decompile the game code

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

To decompile the game code so you can read it (though it won't be fully functional due to decompiler limitations):

  • On Windows:
    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.
  • On Linux/Mac:
    1. Open StardewValley.exe in MonoDevelop through File > Open.
    2. Change Language from Summary to C#.

To unpack the XNB data/image files, see Modding:Editing XNB files.