Skip to content

Latest commit

 

History

History
 
 

README.md

Automate is a Stardew Valley mod which lets you place a chest next to machines (like a furnace, cheese press, bee house, etc), and the machines will automatically pull raw items from the chest and push processed items into it.

Contents

Install

  1. Install the latest version of SMAPI.
  2. Install this mod from Nexus mods.
  3. Run the game using SMAPI.

Use

Basic automation

Place a chest next to a crafting machine (in any direction including diagonal) to connect it. Machines connected to a chest will push their output into it, and pull ingredients to process out of it.

This can be used to automate...

Automated machines will give you the same XP, achievements, and items you'd get for using them directly. If multiple chests are part of a group, they'll all be used in the automation. Input will be taken from all the chests, and output will be saved to chests in this order:

  1. chests marked as output chests (see _Configure);
  2. chests which already contain an item of the same type;
  3. any chest.

You can combine any number of chests and machines by placing them adjacent to each other, and you can press U (configurable) to highlight connected machines.

Factories

A 'factory' is just a machine group which produces a certain output. Here are some example factories. You can increase production by just adding more machines.

  • Automatic crab pots
    A worm bin produces bait, which is fed into the crab pots, which harvest fish and recycle trash. The final products are stored in the chest.

  • Automatic refined quartz factory
    A crystalarium produces quartz, which is smelted into refined quartz, which is stored in the chest.

  • Automatic iridium mead factory
    A bee house produces honey, which is turned into mead, which is aged to iridium quality, which is stored in the chest.

  • Automatic iridium bar factory
    A statue of perfection produces iridium ore, which is smelted into bars, which are stored in the chest.

  • Semi-automatic iridium cheese factory
    Put your milk in the chest and it'll be turned into cheese, then aged to iridium quality, then put back in the chest.

Connectors

You can optionally configure objects or paths as connectors, which link machines together. For example, here are wooden paths used as connectors:

Workbenches are the only connectors by default. You can edit the config.json to add connectors (see configure below).

Configure

config.json

The mod creates a config.json file in its mod folder the first time you run it. You can open that file in a text editor to configure the mod.

These are the available settings:

setting what it affects
Controls

The configured controller, keyboard, and mouse buttons (see key bindings). You can separate multiple buttons with commas. The default value is U to toggle the automation overlay.

AutomateShippingBin

Default true. Whether the shipping bin should automatically pull items out of connected chests.

PullGemstonesFromJunimoHuts

Default false. Whether to pull gemstones out of Junimo huts. If true, you won't be able to change Junimo colors by placing gemstones in their hut.

AutomationInterval

Default 60. The number of update ticks between each automation cycle (one second is ≈60 ticks).

ConnectorNames

Default empty. A list of placed item names to treat as connectors which connect adjacent machines together. You must specify the exact English names for any in-game items to use. For example:

"ConnectorNames": [
   "Wood Path",
   "Crystal Path"
]
ModCompatibility

Enables compatibility with other mods. All values are enabled by default.

field result
AutoGrabberMod If Auto-Grabber Mod is installed, auto-grabbers won't output fertilizer and seeds.
BetterJunimos If Better Junimos is installed, Junimo huts won't output fertilizer and seeds.

In-game settings

Installing Chests Anywhere too lets you set per-chest options directly in-game:

This adds four options for automate:

  • Put items in this chest first: Automate will only push machine output into this chest (until it's full).
  • Don't put items in this chest: Automate won't push any machine output into this chest.
  • Don't take items from this chest: Automate won't take machine input from this chest.
  • Don't use this chest for automation: Automate will completely ignore the chest, so it won't be connected to any machines.

If you don't have Chests Anywhere installed, you can edit the chest names a different way and use these substrings: |automate:output| (put items in this chest first) or |automate:ignore| (don't use this chest in automation).

Compatibility

Automate is compatible with Stardew Valley 1.3+ on Linux/Mac/Windows, both single-player and multiplayer. In multiplayer mode, only the main player can automate machines; other players can keep it installed and use the overlay, their mod just won't automate anything.

Automate is compatible with...

FAQs

What's the order of processed machines?

The order that machines are processed is essentially unpredictable for players. It depends on the internal algorithm for finding machines, which is subject to change.

What's the order of items taken from chests?

For each machine, the available chests are combined into one inventory (so items may be taken from multiple chests simultaneously) and then scanned until Automate finds enough items to fill a recipe for that machine. The order is difficult to predict with multiple chests, but fairly easy if there's only one connected chest.

For example, let's say you have one chest containing these item stacks:
coal
3× copper ore
3× iron ore
2× copper ore
2× iron ore

A furnace has two recipes with those ingredients: coal + 5× copper ore = copper bar, and coal + 5× iron ore = iron bar. Automate will scan the items from left to right and top to bottom, and collect items until it has a complete recipe. In this case, the furnace will start producing a copper bar:

  1. Add coal from first stack (two unfinished recipes):
    coal + 0 of 5× copper ore = copper bar
    coal + 0 of 5× iron ore = iron bar
  2. Add 3× copper ore from second stack (two unfinished recipes):
    coal + 3 of 5× copper ore = copper bar
    coal + 0 of 5× iron ore = iron bar
  3. Add 3× iron ore from third stack (two unfinished recipes):
    coal + 3 of 5× copper ore = copper bar
    coal + 3 of 5× iron ore = iron bar
  4. Add 2× copper ore from fourth stack (one recipe filled):
    coal + 5× copper ore = copper bar
    coal + 3 of 5× iron ore = iron bar

Which chest will machine output go into?

The available chests are sorted by discovery order (which isn't predictable), then prioritised in this order:

  1. chests with the "Put items in this chest first" option (see In-game settings);
  2. chests which already contain an item of the same type;
  3. any chest.

Is there a limit to how many machines can be connected?

Automate optimises machine connections internally, so there's no upper limit. The most I've tried is 630 machines in one group; that didn't cause any issues, so you can just keep adding more if you want.

What if I don't want a specific chest to be connected?

See In-game settings.

Extensibility for modders

Automate has a mod-provided API you can use to add custom machines, containers, and connectors.

Basic concepts

These basic concepts are core to the Automate API:

Entity
A placed item, terrain feature, building, or other in-game thing.
Connector
Something which can be added to a machine group (thus extending its range), but otherwise has no logic of its own. It has no state, input, or output.
Container
Something which stores and retrieves items (usually a chest).
Machine
Something which has a state (e.g. empty or processing) and accepts input, provides output, or both. This doesn't need to be a 'machine' in the gameplay sense; Automate provides default machines for shipping bins and fruit trees, for example.
Machine group

A set of machines, containers, and connectors which are chained together. You can press U in-game (configurable) to see machine groups highlighted in green. For example, these are two machine groups:

Access the API

To access the API:

  1. Add a reference to the Automate.dll file. Make sure it's not copied to your build output.
  2. Hook into SMAPI's GameLoop.GameLaunched event and get a copy of the API:
    IAutomateAPI automate = this.Helper.ModRegistry.GetApi<IAutomateAPI>("Pathoschild.Automate");
  3. Use the API to extend Automate (see below).

Add connectors, containers, and machines

You can add automatables by implementing an IAutomationFactory. Automate will handle the core logic (like finding entities, linking automatables into groups, etc); you just need to return the automatable for a given entity. You can't change the automation for an existing automatable though; if Automate already has an automatable for an entity, it won't call your factory.

First, let's create a basic machine that transmutes an iron bar into gold in two hours:

using Microsoft.Xna.Framework;
using Pathoschild.Stardew.Automate.Framework;
using StardewValley;
using SObject = StardewValley.Object;

namespace YourModName
{
    /// <summary>A machine that turns iron bars into gold bars.</summary>
    public class TransmuterMachine : IMachine
    {
        /*********
        ** Fields
        *********/
        /// <summary>The underlying entity.</summary>
        private readonly SObject Entity;


        /*********
        ** Accessors
        *********/
        /// <summary>The location which contains the machine.</summary>
        public GameLocation Location { get; }

        /// <summary>The tile area covered by the machine.</summary>
        public Rectangle TileArea { get; }


        /*********
        ** Public methods
        *********/
        /// <summary>Construct an instance.</summary>
        /// <param name="entity">The underlying entity.</param>
        /// <param name="location">The location which contains the machine.</param>
        /// <param name="tile">The tile covered by the machine.</param>
        public TransmuterMachine(SObject entity, GameLocation location, in Vector2 tile)
        {
            this.Entity = entity;
            this.Location = location;
            this.TileArea = new Rectangle((int)tile.X, (int)tile.Y, 1, 1);
        }

        /// <summary>Get the machine's processing state.</summary>
        public MachineState GetState()
        {
            if (this.Entity.heldObject.Value == null)
                return MachineState.Empty;

            return this.Entity.readyForHarvest.Value
                ? MachineState.Done
                : MachineState.Processing;
        }

        /// <summary>Get the output item.</summary>
        public ITrackedStack GetOutput()
        {
            return new TrackedItem(this.Entity.heldObject.Value, onEmpty: item =>
            {
                this.Entity.heldObject.Value = null;
                this.Entity.readyForHarvest.Value = false;
            });
        }

        /// <summary>Provide input to the machine.</summary>
        /// <param name="input">The available items.</param>
        /// <returns>Returns whether the machine started processing an item.</returns>
        public bool SetInput(IStorage input)
        {
            if (input.TryGetIngredient(SObject.ironBar, 1, out IConsumable ingredient))
            {
                ingredient.Take();
                this.Entity.heldObject.Value = new SObject(SObject.goldBar, 1);
                this.Entity.MinutesUntilReady = 120;
                return true;
            }

            return false;
        }
    }
}

Next, let's create a factory which returns the new machine. This example assumes you've added an in-game object with ID 2000 that you want to automate.

using Microsoft.Xna.Framework;
using StardewValley;
using StardewValley.Buildings;
using StardewValley.Locations;
using StardewValley.TerrainFeatures;
using SObject = StardewValley.Object;

namespace YourModName
{
    public class MyAutomationFactory : IAutomationFactory
    {
        /// <summary>Get a machine, container, or connector instance for a given object.</summary>
        /// <param name="obj">The in-game object.</param>
        /// <param name="location">The location to check.</param>
        /// <param name="tile">The tile position to check.</param>
        /// <returns>Returns an instance or <c>null</c>.</returns>
        public IAutomatable GetFor(SObject obj, GameLocation location, in Vector2 tile)
        {
            if (obj.ParentSheetIndex == 2000)
                return new TransmuterMachine(obj, location, tile);

            return null;
        }

        /// <summary>Get a machine, container, or connector instance for a given terrain feature.</summary>
        /// <param name="feature">The terrain feature.</param>
        /// <param name="location">The location to check.</param>
        /// <param name="tile">The tile position to check.</param>
        /// <returns>Returns an instance or <c>null</c>.</returns>
        public IAutomatable GetFor(TerrainFeature feature, GameLocation location, in Vector2 tile)
        {
            return null;
        }

        /// <summary>Get a machine, container, or connector instance for a given building.</summary>
        /// <param name="building">The building.</param>
        /// <param name="location">The location to check.</param>
        /// <param name="tile">The tile position to check.</param>
        /// <returns>Returns an instance or <c>null</c>.</returns>
        public IAutomatable GetFor(Building building, BuildableGameLocation location, in Vector2 tile)
        {
            return null;
        }

        /// <summary>Get a machine, container, or connector instance for a given tile position.</summary>
        /// <param name="location">The location to check.</param>
        /// <param name="tile">The tile position to check.</param>
        /// <returns>Returns an instance or <c>null</c>.</returns>
        /// <remarks>Shipping bin logic from <see cref="Farm.leftClick"/>, garbage can logic from <see cref="Town.checkAction"/>.</remarks>
        public IAutomatable GetForTile(GameLocation location, in Vector2 tile)
        {
            return null;
        }
    }
}

And finally, add your factory to the automate API (see access the API above):

IAutomateAPI automate = ...;
automate.AddFactory(new MyAutomationFactory());

That's it! When Automate scans a location for automatables, it'll call your GetFor method and add your custom machine to its normal automation.

See also