Autofarms
This page uses Vector3 from Unity. The glossary says what each one is.
What it is
An autofarm is a machine in the game that plants crops by itself. It fills its growing slots with plants when a scene starts and again at set times of the week. This API lets your mod list the autofarms in the scene you are in, read what each one grows, change how grown its next plants start, and get told when one plants. The plants themselves, their age and their harvest are on the recipes page under Plants, not here.
When to use it
- Show how many slots each autofarm has and how many are planted.
- Make the next plants an autofarm plants start fully grown, or barely grown.
- Run your own code each time an autofarm plants something.
Quick example
This mod logs every autofarm in the scene once a save is loaded, and logs a line each time one plants.
using ObenseuerCore;
[ModInfo("example.farmwatch", "Farm Watch", "0.1.0")]
[ModDependency("obenseuer.moddingframework", "0.11.0")]
public sealed class FarmWatch : FrameworkMod
{
protected override void OnLoad()
{
Autofarms.Replanted += args => Log.Info("Autofarm " + args.AutofarmId + " planted " + args.PlantedCount + " plants.");
Events.WhenReady(() =>
{
foreach (AutofarmInfo farm in Autofarms.All())
Log.Info("Autofarm " + farm.Id + ": " + farm.PlantedCount + " of " + farm.SlotCount + " slots planted.");
});
}
}
Replanted is an event: the framework calls your code each time it happens. See Using events for more on events and WhenReady.
Common tasks
Make every autofarm in the scene plant crops that start at least half grown. This only affects plants the autofarm plants from now on.
foreach (AutofarmInfo farm in Autofarms.All())
Autofarms.SetGrowPercentage(farm.Id, 50, 100);
Set the growth again after every scene load, because the game does not save it.
Events.SceneLoaded += scene =>
{
foreach (AutofarmInfo farm in Autofarms.All())
Autofarms.SetGrowPercentage(farm.Id, 50, 100);
};
Look at one autofarm and the plants it chooses from.
AutofarmInfo farm = Autofarms.Get("some-id");
if (farm != null) Log.Info(farm.PlantItemIds.Count + " kinds of plant, filled " + (farm.PlantInOrder ? "in order" : "at random"));
Reference
This is the full list of what the API gives you. Text in brackets at the end of a note is extra detail you can skip on a first read.
Each autofarm is an AutofarmInfo, a snapshot of its state at the moment you asked. The snapshot does not update by itself, so ask again for fresh values. Replanted tells you when an autofarm plants.
Autofarms lists autofarms and their planting
Use All or Get to find autofarms, SetGrowPercentage to change how grown their next plants start, and Replanted to hear when one plants.
public static class Autofarms
{
public static List<AutofarmInfo> All();
public static AutofarmInfo Get(string id);
public static bool SetGrowPercentage(string id, int min, int max);
public static bool IsAvailable { get; }
public static event Action<ReplantedArgs> Replanted;
}
| Method | Returns | What it does |
|---|---|---|
All() | List<AutofarmInfo> | Every autofarm in the scene you are in. |
Get(id) | AutofarmInfo | The autofarm with this id. null when none has it. |
SetGrowPercentage(id, min, max) | bool | Sets how grown the next plants start. false when no autofarm has the id. |
| Property | Type | What it means |
|---|---|---|
IsAvailable | bool | false when the planting event could not be set up. |
| Event | Gives you | When it fires |
|---|---|---|
Replanted | ReplantedArgs | An autofarm has just planted something. |
AutofarmInfo a snapshot of one autofarm
All and Get give you one of these for each autofarm. It is a snapshot, so ask again for fresh values.
public sealed class AutofarmInfo
{
public string Id { get; }
public Vector3 Position { get; }
public int SlotCount { get; }
public int PlantedCount { get; }
public List<int> PlantItemIds { get; }
public bool PlantInOrder { get; }
public int GrowPercentageMin { get; }
public int GrowPercentageMax { get; }
public int OwnerId { get; }
}
| Property | Type | What it means |
|---|---|---|
Id | string | The autofarm’s id: its save id, or its place in the scene when it has none. |
Position | Vector3 | Where the autofarm is, in world coordinates. |
SlotCount | int | How many growing slots the machine fills. |
PlantedCount | int | How many slots hold a plant right now. |
PlantItemIds | List<int> | The item ids of the plants it chooses from. |
PlantInOrder | bool | true: it fills slots in order. false: it picks plants at random. |
GrowPercentageMin | int | The lowest starting growth for a new plant, in percent. |
GrowPercentageMax | int | The highest starting growth for a new plant, in percent. |
OwnerId | int | The id of the NPC who owns the autofarm. 0 when nobody does. |
ReplantedArgs what you get when an autofarm plants
Replanted hands you this each time an autofarm plants. PlantedCount says how many slots the planting filled, and Initial is true for the first planting of a new autofarm.
public sealed class ReplantedArgs
{
public string AutofarmId { get; }
public int PlantedCount { get; }
public bool Initial { get; }
}
| Property | Type | What it means |
|---|---|---|
AutofarmId | string | The id of the autofarm that planted. |
PlantedCount | int | How many slots this planting filled. |
Initial | bool | true for the first planting of a brand new autofarm. |
Things to know
All()lists every autofarm in the scene you are in.Get(id)gives you one autofarm, ornullwhen no autofarm has that id. (both scan the active scene withFindObjectsByType)- Plant item ids are the plain whole-number ids used everywhere in the framework. The game also stores a namespace with each plant, and the framework does not give it to you. (the numbers are
ItemReference.ID; the reference’sitemnamespaceis not available to mods) SetGrowPercentage(id, min, max)changes how grown the next plants start. Plants already in the slots keep their growth, and only later plantings use the new range.- You can call
SetGrowPercentageat any time, including while a save is loading or being written. Replantedfires when a planting fills at least one empty slot. It fires for the first planting of a new autofarm (Initialistrue) and for each planting at the autofarm’s set times (Initialisfalse).- A planting that finds no empty slot, or has nothing to plant, does not fire
Replanted. - An autofarm from a loaded save already did its first planting, so it does not plant when the scene starts. (
Initialis true while the game’sinitDonefield is still false; a loaded save hasinitDoneset)
Limits
All()is slow, because it searches the whole scene each time, and so doesGet. Do not callAll()every frame. Call it when something happens, or on a timer, and keep the result.SetGrowPercentagerequiresminto be from0to100, andmaxto be fromminto100. Anything else throws anArgumentException.- The growth range is not saved, so set it again after every scene load. The game does not keep it in the save, so when a save loads, the range goes back to the scene’s own values. Call
SetGrowPercentageagain fromEvents.SceneLoaded, as in the second task above. (Autofarm.growPercentageMinandgrowPercentageMaxare marked[fsIgnore], which keeps them out of the game’s save) Replantedalso fires while a save is loading. If your handler should ignore those, checkSaveData.Busy, which istruewhile a save is loading or being written.- You can’t read or change the planting times. The days and hours an autofarm plants at are not available to mods yet. (
Autofarm.replantTimes, an array of the game’sWeekdayAndHour) - You can’t change which plants an autofarm uses, who owns it, whether it plants in order, or its slots. Only the growth range can be changed. It is a plain value the game reads on every planting. (
plantPrefabs,ownerId,plantInOrderand the growing slots are not written by the framework) - You can’t make an autofarm plant or harvest by hand. The game’s planting method is private. To react to a harvest, use
Plants.Harvested. (Autofarm.Plantis private)
Details
Target: Obenseuer 0.5.08 (buildid 25969064), Unity 6000.0.77f1 Mono, BepInEx 6 Unity.Mono (be.788, the tested build) or BepInEx 5 (5.4.23 or later). Namespace: ObenseuerCore. Source: src/Api/Autofarms.cs and src/Api/AutofarmsPatches.cs.
Everything not listed in this reference is internal and may change without notice.
- The framework changes one of the game’s methods when it starts, so it can tell your mod when an autofarm plants.
- Its feature group, the name you will see in the log, is
obenseuer.moddingframework.autofarms.
When you can call it
- Call everything from your mod’s normal code (
OnLoad, event handlers,Update), not from a background thread you started. The game only runs safely on the main thread (see the glossary). - It is safe to call any of it at any time. With no save loaded, or on the main menu,
All()gives an empty list,GetgivesnullandSetGrowPercentagegivesfalse. The only call that throws isSetGrowPercentage, for a growth range that is not allowed. Autofarms.IsAvailabletells you whetherReplantedworks. It isfalsewhen the framework could not set up the planting event, or when the feature group was turned off. The reads andSetGrowPercentagekeep working when it isfalse.- Your
Replantedhandler runs inside the game’s own planting call. If your handler throws an error, the framework logs it and still runs the other handlers. (the event is raised from a Harmony postfix (a piece of code that runs right after the game method) onAutofarm.Plant, on the main thread)
If something fails to set up
- The framework changes some of the game’s methods when it starts. If a game update breaks one of them, the framework turns off the feature group that depends on it, and writes error lines and a warning to the group’s log file in
BepInEx\logs. The rest of the framework keeps working. - If the change to the game’s planting method fails, the feature group turns off and
Replantedstops. One warning goes to the log.All(),GetandSetGrowPercentagekeep working. (the method isAutofarm.Plant. The log line reads “autofarm hooks incomplete, replanted events are disabled”)