, ,

Buy Nothing Mod

Buy Nothing Mod

Why not?

This question came up during our last play session. Building a mod that restricts the player buying anything the first year isn’t a complex change to the game’s world. However, neither of us know how to code so this would be a good chance to see how far we could get with AI. A discussion about AI and modding will be at the end. The only creative change needed to the game’s world should be adding a bit of dialogue for each NPC that stops the player buying things.


Starting Out

We used Perplexity AI to guide us through the process. The model settings were for the best model available. Below are the steps generated by Perplexity followed by our notes about the process.

1. Install SMAPI on macOS

  • Make sure you’re on macOS 10.15 Catalina or later so SMAPI and Stardew’s .NET version work correctly.
  • Download the latest SMAPI for macOS from smapi.io.
  • Unzip it, then right‑click install on Mac.command (or install on macOS.command) and choose Open, then follow the prompts to point it at your Stardew Valley app.
  • After it finishes, launch Stardew once via Steam like normal; SMAPI will open in Terminal and show a console window when it’s working.

Your Mods folder will usually end up under:

  • ~/Library/Application Support/Steam/steamapps/common/Stardew Valley/Contents/MacOS/Mods for Steam installs.

The directions included links and SDV wiki’s directions are pretty close to being idiot proof. Link: https://stardewvalleywiki.com/Modding:Installing_SMAPI_on_Mac_Pictorial_Guide#Install_SMAPI

I’m a casual user of Macs so it was nice to learn about alias folders on desktops. Started the game with SMAPI installed and had no issues.

2. Set up your C# dev tools on Mac

You have two main options:

  • Visual Studio for Mac (if you already use it) or
  • Visual Studio Code + .NET SDK, which is lightweight and works well on macOS.

For VS Code:

  • Install the .NET SDK that matches Stardew’s SMAPI requirements (NET 6 / NET 5 depending on your versions) plus the C# and .NET support extensions.
  • Follow a short setup like the “Building Stardew Valley Mods using SMAPI in VS Code” guide: it walks through creating a C# library project, adding SMAPI references, and setting up build tasks on macOS.

The directions offered a few different tutorials to follow and I found this to be the most helpful: https://stardewvalleywiki.com/Modding:Modder_Guide/Get_Started

I wanted to try a non-microsoft option, so I went with Jetbrains software Rider: https://www.jetbrains.com/rider/

This required updating Perplexity’s directions to be specifically for this software. It really pushed the Microsoft products on me. Perplexity’s new responses pointed me in the right direction but wasn’t very specific about what to do exactly for each step.

3. Create a new Stardew SMAPI mod project in Rider

3.1. New project

  1. In Rider: File → New Solution.
  2. Choose .NET → Class Library (or “Console Application” and then change to Class Library later, but Class Library is ideal).
  3. Name it something like NoCommerceYearOne and pick a location you like (not inside the game folder).
  4. Target framework: pick the same .NET you see listed in Stardew/SMAPI docs (usually net6.0 with current versions).

Rider will create:

  • .csproj file.
  • A default Class1.cs file.

You’ll replace that with your ModEntry class.

3.2. Add references to Stardew and SMAPI

You need Rider to know about the game and SMAPI assemblies.

  1. Locate your Stardew + SMAPI install on Mac:
    • For Steam, it’s usually under ~/Library/Application Support/Steam/steamapps/common/Stardew Valley/Contents/MacOS/ (with the Stardew Valley.app bundle structure).
  2. Inside the app bundle, find the Stardew Valley.dll and StardewModdingAPI.dll (often in Contents/Resources or same folder as the game executable).
  3. In Rider, right‑click your project → Add → Add Reference….
  4. Choose Browse, navigate to those DLLs, and add:
    • StardewModdingAPI.dll
    • Stardew Valley.dll

Rider now knows all the SMAPI and game types like ModGame1ShopMenu, etc.

This wasn’t 100% intuitive about where to click or verify that I had referenced the two .DLL files correctly. It look a bit of trial and error to make sure I followed the steps correctly.

4. Add your SMAPI manifest and main mod class

4.1. Add manifest.json

  1. Right‑click the project → Add → New File → JSON File and name it manifest.json.
  2. Paste something like:
json{
  "Name": "No Commerce Year One",
  "Author": "YourName",
  "Version": "1.0.0",
  "Description": "Disables buying and selling during year 1.",
  "UniqueID": "yourname.NoCommerceYearOne",
  "EntryDll": "NoCommerceYearOne.dll",
  "MinimumApiVersion": "4.0.0"
}

Make sure EntryDll matches the name of your build DLL (NoCommerceYearOne.dll if that’s your project name).


4.2. Add your ModEntry class

  1. Delete Class1.cs.
  2. Right‑click the project → Add → New C# Class → name it ModEntry.cs.
  3. Paste and adapt the basic SMAPI structure (this is a sketch; we’d refine it once we know your SMAPI version):
csharpusing StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Menus;

namespace NoCommerceYearOne
{
    public class ModEntry : Mod
    {
        public override void Entry(IModHelper helper)
        {
            helper.Events.Display.MenuChanged += OnMenuChanged;
        }

        private void OnMenuChanged(object? sender, MenuChangedEventArgs e)
        {
            if (Game1.year != 1)
                return;

            if (e.NewMenu is ShopMenu shop)
            {
                Game1.ShowRedMessage("No buying or selling in year 1!");

                shop.onPurchase = (item, farmer, amount) =>
                {
                    Game1.showRedMessage("You can't buy anything in year 1.");
                    // Intentionally do nothing: no item added, no money spent.
                };

                // Selling block: this part depends on the ShopMenu API in your SMAPI version.
                // Once you confirm your SMAPI version, we can wire a specific pattern here.
            }
        }
    }
}

This wires into the menu‑change event and modifies shop behavior when Game1.year == 1. The exact selling hook may need adjusting once we look at the current ShopMenu in your SMAPI/game version.

This was easier to follow after figuring out where I needed to add files from. The code has a bunch of errors I’ll have to figure out after I get through all the steps.

5. Configure build output and build the mod in Rider

  1. Open the .csproj in Rider’s editor and confirm the target framework (e.g., <TargetFramework>net6.0</TargetFramework>).
  2. Optional but nice: set the output path to something simple, for example:
xml<PropertyGroup>
  <TargetFramework>net6.0</TargetFramework>
  <OutputPath>bin/SMAPI/</OutputPath>
</PropertyGroup>
  1. Use Build → Build Solution (or the hammer icon).
  2. After a successful build, Rider will show the compiled DLL in bin/SMAPI (or the default bin/Debug/net6.0 if you didn’t change OutputPath).

I got stuck here for over an hour because I didn’t think I had a correct .csproj file. I went through the directions again and got confused about this part in step 3:

Choose .NET → Class Library (or “Console Application” and then change to Class Library later, but Class Library is ideal).

Thinking I missed a step, I reinstalled Rider four times, twice manually and twice through JetBrains Tool Box App (works like Adobe’s Creative Cloud suite). Link here: https://www.jetbrains.com/toolbox-app/. Once I figured out everything was working correctly I asked for help doing step 5 in detail. Below are the directions it gave me.


5a. Open and edit the .csproj in Rider

  1. In Rider’s left panel (Solution/Explorer), find your project (for example NoCommerceYearOne).
  2. Right‑click the project name (the one with the C# icon).
  3. Click Edit Project File. This opens the .csproj XML in the editor.

You’ll see something like:

xml<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <!-- maybe other lines here -->
  </PropertyGroup>
</Project>

(Your TargetFramework might be net8.0net7.0, etc.)


5b. Set TargetFramework and OutputPath

  1. Inside the <PropertyGroup> block, find the <TargetFramework> line.
  2. Change it so it reads exactly:
xml<TargetFramework>net6.0</TargetFramework>

5c. On the next line (still inside the same <PropertyGroup>), add:

xml<OutputPath>bin/SMAPI/</OutputPath>

So the full section looks like:

xml<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <OutputPath>bin/SMAPI/</OutputPath>
  </PropertyGroup>
</Project>

If Rider added extra properties (like ImplicitUsings or Nullable), leave them, just make sure TargetFramework is net6.0 and OutputPath is somewhere inside <PropertyGroup>(order doesn’t matter).


5d. Press ⌘S to save the .csproj.


Getting detailed directions is something I’ve done before in the past with other software that wasn’t user friendly, such as Tableau. Unless your prompt states you have no experience with the software, it assumes a base level of proficiency.

6. Build the mod in Rider

  1. At the top menu, click Build → Build Solution.
    • Or click the hammer icon in the toolbar.
  2. Watch the bottom panel (Build/Problems). Wait until it says Build succeeded with no red errors.

If it says Build failed, copy the first red error line text and I’ll help fix it.

I knew this wasn’t going to work based on the list of errors I saw. I got a “Build Complete” but with 6 errors and 2 warnings.

Errors

0>ModEntry.cs(4,2): Error CS1513 : } expected
0>ModEntry.cs(5,1): Error CS1529 : A using clause must precede all other elements defined in the namespace except extern alias declarations
0>ModEntry.cs(6,1): Error CS1529 : A using clause must precede all other elements defined in the namespace except extern alias declarations
0>ModEntry.cs(7,1): Error CS1529 : A using clause must precede all other elements defined in the namespace except extern alias declarations
0>ModEntry.cs(8,1): Error CS1529 : A using clause must precede all other elements defined in the namespace except extern alias declarations
0>ModEntry.cs(41,1): Error CS1022 : Type or namespace definition, or end-of-file expected

I passed these errors to Perplexity and it gave me new code to try. Below is the code’s second draft.

using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Menus;
namespace NoSellChallenge
{
public class ModEntry : Mod
{
public override void Entry(IModHelper helper)
{
helper.Events.Display.MenuChanged += OnMenuChanged;
}
private void OnMenuChanged(object? sender, MenuChangedEventArgs e)
{
if (Game1.year != 1)
return;
if (e.NewMenu is ShopMenu shop)
{
Game1.ShowRedMessage("No buying or selling in year 1!");
shop.onPurchase = (item, farmer, amount) =>
{
Game1.showRedMessage("You can't buy anything in year 1.");
// Intentionally do nothing: no item purchased.
};
}
}
}
}

Compiling this resulted in two errors. I passed these new errors to Perplexity who gave the following explanation:

Fix the red message call

In newer versions the method is showRedMessage (lowercase s), not ShowRedMessage. Your code currently has:

csharpGame1.ShowRedMessage("No buying or selling in year 1!");

Change it to:

csharpGame1.showRedMessage("No buying or selling in year 1.");

Now both message lines use showRedMessage.

Fix the onPurchase delegate parameters

The signature of ShopMenu.OnPurchaseDelegate in recent Stardew/SMAPI versions is typically:

csharpvoid OnPurchaseDelegate(ISalable item, Farmer who, int amount);

or with extra optional parameters depending on version.

Your error says it doesn’t take 3 arguments, so we’ll drop the amount parameter and accept only the ones SMAPI expects in your version.

Replace this:

csharpshop.onPurchase = (item, farmer, amount) =>
{
    Game1.showRedMessage("You can't buy anything in year 1.");
    // Intentionally do nothing: no item purchased.
};

with this:

csharpshop.onPurchase = (item, farmer) =>
{
    Game1.showRedMessage("You can't buy anything in year 1.");
    // Intentionally do nothing: no item purchased.
};

If Rider then complains it does expect 3 parameters, change it to:

csharpshop.onPurchase = (item, farmer, amount) =>
{
    Game1.showRedMessage("You can't buy anything in year 1.");
};

and we’ll add/remove a parameter based on the exact error text, but try the 2‑parameter version first.


Did these updates and now have one error remaining:

0>ModEntry.cs(24,50): Error CS1593 : Delegate ‘ShopMenu.OnPurchaseDelegate’ does not take 2 arguments

Passed this back to Perplexity and got the following updated instructions:

Update the onPurchase lambda to use all arguments

Change your if (e.NewMenu is ShopMenu shop) block to this version:

csharpif (e.NewMenu is ShopMenu shop)
{
Game1.showRedMessage("No buying or selling in year 1.");

shop.onPurchase = (item, farmer, stack, amountToBuy, stock) =>
{
Game1.showRedMessage("You can't buy anything in year 1.");
// Intentionally do nothing: don't modify money or inventory.
};
}

This matches the newer documented delegate that includes the stock info as extra parameters.

Make sure you remove any old onPurchase = ... line so there’s only this one.


I wasn’t pasting in the full error log, so I ended up getting back and forth with Perplexity’s guesses on how to fix the last error. Pasting the full error log gave me simpler code to try.

using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Menus;

namespace NoSellChallenge
{
public class ModEntry : Mod
{
public override void Entry(IModHelper helper)
{
helper.Events.Display.MenuChanged += OnMenuChanged;
}

private void OnMenuChanged(object? sender, MenuChangedEventArgs e)
{
if (Game1.year != 1)
return;

if (e.NewMenu is ShopMenu)
{
Game1.showRedMessage(“No buying or selling in year 1.”);
Game1.exitActiveMenu();
}
}
}

}

7. Rebuild and test

  1. Save ModEntry.cs.
  2. In Rider, Build → Build Solution.
  3. Confirm there are no red errors (the architecture warnings are OK to ignore for now).

If it builds successfully:

  • Copy your NoBuySellChallenge.dll from bin/SMAPI plus manifest.json into your SMAPI Mods/NoBuySellChallenge folder.
  • Start a new save in Stardew, in year 1, and try to open Pierre’s or any other shop. It should flash the red message and immediately close.

If you later want a more nuanced behavior (e.g., allow opening the shop but silently blocking transactions), we can then look up the exact OnPurchaseDelegate signature from your Stardew Valley.dll using a decompiler and match it precisely, but this version gives you the “no buying or selling for the first year” challenge behavior right now

It worked! Proof of concept pics below. The original challenge was about not buying anything the first year, but I would like to expand it eventually to not selling anything either. That way the player really has to horde resources.


Thoughts on Modding with AI

The entire process took us around 3 – 4 hours. I was shocked at how little code went into setting up a restriction on buying stuff the first year. There was a bit of a learning curve with the software Rider but that’s to be expected.

I think AI was useful in helping work through points where we got stuck, but isn’t a replacement for reading documentation or exploring sites like Stardew Modding Wiki: https://stardewmodding.wiki.gg/wiki/Category:Tutorials

We have no idea what the code did, despite being able to produce something. AI was a good way to get our feet wet, but it shouldn’t supplement the learning process or thinking critically. Still, it was cool to see the code behind the game we love!

Welcome!

This is a Stardew Valley fan site. We write about play through challenges in-depth and explore fan made products.

About

Made by two friends who still love the game after a combined 510 hours. We started this site because we found most SDV challenges are the same lists repeated over and over. Our take on challenges involves discussing the impact to the game’s world.