Difference between revisions of "Modding:Modder Guide/Tutorial Mod"
Pathoschild (talk | contribs) m (Pathoschild moved page Modding:Creating a SMAPI mod to Modding:Modder Guide/Tutorial Mod: Move into modder's guide) |
Pathoschild (talk | contribs) (integrate into modder's guide, move some content to intro page, rewrite and expand a bit) |
||
Line 1: | Line 1: | ||
− | + | {{../header}} | |
− | + | '''See [[Modding:Modder Guide]] for an intro before reading this page. This page assumes you've already installed the software mentioned on that page.''' | |
+ | |||
+ | This page will help you create your first SMAPI mod. The mod won't do much on its own (just detect user input and print a message to the console), but it'll be fully functional and provide a base you can expand from. | ||
==Quick start== | ==Quick start== | ||
Line 9: | Line 11: | ||
# Target .NET Framework 4.5 (for Linux compatibility). | # Target .NET Framework 4.5 (for Linux 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. | # 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 | + | # 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]]. | # 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 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 [[#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. | 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. | # 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 solution with a .NET Framework class library project (see [[Modding:IDE reference#create-project|how to create a project]]). |
− | # Change the target framework to .NET Framework 4.5 for compatibility with Linux (see [[Modding:IDE reference#set-target-framework|how to]]). | + | # Change the target framework to .NET Framework 4.5 for compatibility with Linux (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]]). | + | # 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]]). |
#* '''Stardew Valley 1.3 only:''' make sure you install the latest 2.1-beta version of the package. (You may need to enable the 'include prerelease' checkbox above the search results to see it.) | #* '''Stardew Valley 1.3 only:''' make sure you install the latest 2.1-beta version of the package. (You may need to enable the 'include prerelease' checkbox above the search results to see it.) | ||
# Restart Visual Studio/MonoDevelop after installing the package. | # Restart Visual Studio/MonoDevelop after installing the package. | ||
− | === | + | ===Add the code=== |
− | + | Next let's add some code SMAPI will run. | |
<ol> | <ol> | ||
− | <li>Delete the <tt>Class1.cs</tt> or <tt>MyClass.cs</tt> file (see [[Modding:IDE reference#delete-file|how to]]).</li> | + | <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]]).</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): | <li>Put this code in the file (replace <tt>YourProjectName</tt> with the name of your project): | ||
<source lang="c#"> | <source lang="c#"> | ||
Line 94: | Line 56: | ||
InputEvents.ButtonPressed += this.InputEvents_ButtonPressed; | InputEvents.ButtonPressed += this.InputEvents_ButtonPressed; | ||
} | } | ||
+ | |||
/********* | /********* | ||
Line 103: | Line 66: | ||
private void InputEvents_ButtonPressed(object sender, EventArgsInput e) | private void InputEvents_ButtonPressed(object sender, EventArgsInput e) | ||
{ | { | ||
− | if (Context.IsWorldReady) // | + | // 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}."); | ||
} | } | ||
} | } | ||
Line 113: | Line 78: | ||
</ol> | </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=== | ===Add your manifest=== | ||
Line 157: | Line 115: | ||
===Troubleshooting=== | ===Troubleshooting=== | ||
− | If | + | 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]]. :) | ||
− | == | + | ==Things to consider== |
===Crossplatform support=== | ===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: | 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: | ||
Line 236: | Line 194: | ||
To unpack the XNB data/image files, see [[Modding:Editing XNB files]]. | To unpack the XNB data/image files, see [[Modding:Editing XNB files]]. | ||
− | |||
− |
Revision as of 17:46, 27 May 2018
- Get started
- Game fundamentals
- Test & troubleshoot
- Release
- API reference
- Basic SMAPI APIs:
- Advanced SMAPI APIs:
- Specific guides
See Modding:Modder Guide for an intro before reading this page. This page assumes you've already installed the software mentioned on that page.
This page will help you create your first SMAPI mod. The mod won't do much on its own (just detect user input and print a message to the console), but it'll be fully functional and provide a base you can expand from.
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 (for Linux compatibility).
- Reference the Pathoschild.Stardew.ModBuildConfig NuGet package to automatically add the right references depending on the platform the mod is being compiled on.
- Create a ModEntry class which subclasses StardewModdingAPI.Mod.
- Override the Entry method, and write your code using the SMAPI events and APIs.
- Create a manifest.json file which describes your mod for SMAPI.
- 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.
- Open Visual Studio 2017 or MonoDevelop.
- Create a solution with a .NET Framework class library project (see how to create a project).
- Change the target framework to .NET Framework 4.5 for compatibility with Linux (see how to change target framework).
- Reference the Pathoschild.Stardew.ModBuildConfig NuGet package (see how to add the package).
- Stardew Valley 1.3 only: make sure you install the latest 2.1-beta version of the package. (You may need to enable the 'include prerelease' checkbox above the search results to see it.)
- Restart Visual Studio/MonoDevelop after installing the package.
Add the code
Next let's add some code SMAPI will run.
- Delete the Class1.cs or MyClass.cs file (see how to delete a file).
- Add a C# class file called ModEntry.cs to your project (see how to add a file).
- 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:
using X;
(see using directive) makes classes in that namespace available in your code.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.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.public override void Entry(IModHelper helper)
is the method SMAPI will call when your mod is loaded into the game. Thehelper
provides convenient access to many of SMAPI's APIs.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.
- Add a file named manifest.json to your project.
- 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
- Build the project.
If you did the create the project steps correctly, this will automatically add your mod to the game's Mods folder. - 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 in the Stardew Valley Discord. :)
Things to consider
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:
- 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.)
- 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");
- 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;
Test on all platforms
If you want to test your mod on all platforms, there's some first-time setup you need to get out of the way. Essentially you need to test your mod twice: once on Windows, and again on Linux or Mac. You can do that by testing one version on your computer, and the other in a virtual machine.
- If your main computer is Windows:
- Install VirtualBox.
- Add this premade Linux virtual machine (requires a 64-bit computer).
In VirtualBox, click Machine » Add and choose the downloaded .vbox file. This is a Manjaro virtual machine with Chromium (web browser), Steam, and MonoDevelop preinstalled. - Launch the virtual machine, and install Stardew Valley from the Steam client (preinstalled) or GOG website.
Tip: don't change the default install path, or you'll need to customise the mod's build configuration.
- If your main computer is Linux or Mac:
- Install VirtualBox.
- Create a VM with Windows.
- Install Visual Studio Community in your VM.
- Install Stardew Valley in your VM.
Release your mod
Ready to share your mod with the world? Here's how:
- Open your project's bin/Debug or bin/Release folder (depending on your build configuration).
- There should be a .zip file there for your mod version.
- Upload that file to Nexus Mods.
In your mod description, providing clear install steps will help reduce support questions. Example BBCode:
[size=5]Install[/size] [list=1] [*][url=https://smapi.io]Install the latest version of SMAPI[/url]. [*]Download this mod and unzip it into [font=Courier New]Stardew Valley/Mods[/font]. [*]Run the game using SMAPI. [/list]
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 StardewValley.exe in 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 StardewValley.exe in MonoDevelop through File > Open.
- Change Language from Summary to C#.
To unpack the XNB data/image files, see Modding:Editing XNB files.