Plant actions

This page uses KeyCode from Unity. The glossary says what each one is.

What it is

Plants grow in growing spots, such as the beds of a growing station. This API lets your mod change a single plant: harvest it, restart it, set how old it is, change how old it must be to be ripe, pause it, make it rot, or plant a new one in an empty spot. It can also pick up a plant that the player takes by hand. Listing the plants and getting told about a harvest are on the Recipes page (Plants.All, Plants.Harvested, Plants.Picked). Plant ids are the ids that Plants.All gives you. To act on a whole station at once, use Growing stations.

When to use it

  • Harvest a plant for the player, or harvest every ripe plant.
  • Make a plant ripe at once, or restart it.
  • Change how long a plant takes to grow.
  • Pause a plant, or make it rot.
  • Put a new plant in an empty growing spot.
  • Pick up a plant that is picked by hand.

Quick example

This mod waits for you to press F8. Then it harvests every plant in the scene that is fully grown, and logs how many it harvested.

using ObenseuerCore;
using UnityEngine;

[ModInfo("example.harvestall", "Harvest All", "0.1.0")]
[ModDependency("obenseuer.moddingframework", "0.11.0")]
public sealed class HarvestAll : FrameworkMod
{
    private ModKeybind harvestKey;

    protected override void OnLoad()
    {
        harvestKey = Mod.Key("Harvest", "Harvest every ripe plant", KeyCode.F8);
    }

    private void Update()
    {
        if (harvestKey == null || UiState.IsMenuOpen || UiState.IsPaused || UiState.IsInputBlocked) return;
        if (!harvestKey.Down()) return;
        int harvested = 0;
        foreach (PlantInfo plant in Plants.All())
        {
            if (plant.FullyGrown && PlantActions.Harvest(Mod.Id, plant.Id)) harvested++;
        }
        Log.Info("Harvested " + harvested + " plants.");
    }
}

Every call takes your mod’s id first, which is Mod.Id. Each call gives back true when it did the job and false when it did not. See the keybinds guide for Mod.Key.

Common tasks

Make a plant fully grown, then harvest it. In the next snippets, plantId is the Id of a plant from Plants.All().

PlantActions.SetAgePercent(Mod.Id, plantId, 100);
PlantActions.Harvest(Mod.Id, plantId);

Make a plant ripen faster by lowering the age it must reach.

PlantActions.SetFullGrownAge(Mod.Id, plantId, 5);

Stop a plant from growing, and let it grow again.

PlantActions.Pause(Mod.Id, plantId, true);
PlantActions.Pause(Mod.Id, plantId, false);

Plant an item in an empty growing spot. spotId is the SpotId of the spot and itemId is the id of an item that grows.

if (!PlantActions.Plant(Mod.Id, spotId, itemId)) Log.Info("Nothing was planted.");

Pick up a plant that is picked by hand. See Growing stations for how to find the spot.

PlantActions.HarvestSpot(Mod.Id, spotId);

Reference

This is the full list of what the API gives you. Text in brackets at the end of a note is extra detail for experienced modders, and you can skip it on a first read.

The calls

PlantActions change one plant or one growing spot

Use it to harvest a plant, reset or pause its growth, change its age or rot, plant an item in an empty growing spot, or pick up a plant that was picked by hand.

public static class PlantActions
{
    public static bool Harvest(string modId, string plantId);
    public static bool Reset(string modId, string plantId);
    public static bool SetAgePercent(string modId, string plantId, int percent);
    public static bool SetFullGrownAge(string modId, string plantId, int age);
    public static bool Pause(string modId, string plantId, bool paused);
    public static bool SetRotting(string modId, string plantId, bool rotting);
    public static bool Plant(string modId, string spotId, int itemId);
    public static bool HarvestSpot(string modId, string spotId);
}
Method Returns What it does
Harvest(modId, plantId) bool Harvests a plant the way the player does.
Reset(modId, plantId) bool Sets the plant’s age back to 0.
SetAgePercent(modId, plantId, percent) bool Sets the age as a percent of full grown, from 0 to 100.
SetFullGrownAge(modId, plantId, age) bool Sets the age at which the plant is ripe.
Pause(modId, plantId, paused) bool Stops or restarts the plant’s growth.
SetRotting(modId, plantId, rotting) bool Starts or stops the plant’s rot.
Plant(modId, spotId, itemId) bool Plants an item in an empty growing spot.
HarvestSpot(modId, spotId) bool Picks up a plant that is picked by hand.

In these calls, modId is the id of your mod, plantId is the id of a plant from Plants.All, and spotId is the id of a growing spot.

Harvesting

  • Harvest takes the plant’s crop the way the player does. The items go to the player’s inventory, and onto the floor when the inventory is full. Plants.Harvested fires when the call hands out a crop.
  • A plant with ripe fruit works differently. The game picks the fruit and gives no crop, so Plants.Picked fires once for each fruit, and Plants.Harvested does not fire. (The check is whether any visible grown item is active and readyToPick.)
  • A plant that is not ripe gives a smaller crop, scaled by its age. The plant is then restarted or removed, as the game does. A plant that is removed this way also empties its growing spot.
  • Harvest gives false when the call handed out no items. This happens, for example, when the smaller crop of a young plant rounds down to nothing. The plant is still restarted or removed in that case.
  • Reset sets the plant’s age back to 0, as the game does after a pick.
  • HarvestSpot picks up a plant that is picked by hand, and Harvest is for the plants that grow. A plant picked by hand is one with no growth of its own, so it has no age. HarvestSpot does what the player’s pick-up does. The items go to the inventory, and the game’s warning shows when the inventory is full. (Such a plant is a CollectibleItem in a growing spot with no grow component. It runs the game’s CollectibleItem.PerformPickup.)
  • HarvestSpot gives true when everything was picked up, and the spot is then empty. If only part of it fits in the inventory, the part that fits is added, the rest stays on the plant, and you get false. It also gives false for a spot with no plant and for a plant that grows (use Harvest for that).
  • Plants.Harvested does not fire for HarvestSpot.

Changing a plant

  • SetAgePercent sets the age as a percent of the age at which the plant is ripe. The percent must be from 0 to 100. Any other value gives false. Only the age changes. The plant’s look catches up the next time it grows.
  • SetFullGrownAge sets how old the plant must be to be ripe, in the same unit as the plant’s age. It is set for that one plant, and it is saved with it. Plants.All shows the value as PlantInfo.FullGrownAge. If the plant’s age is above the new value, the age is lowered to it. The call gives false for an age below 1, and for a plant id that matches no plant. (The growth stage models keep the timing they had when the plant started, so the look can lag the new age until the plant is created again.)
  • Pause stops or restarts the plant’s growth, but a rotting plant ignores it. The growing station’s own pause and unpause change the same setting, so a station can undo your pause. A rotting plant keeps rotting whatever you set. (It sets the plant’s Paused flag, and the game skips Paused while the plant is rotting.)
  • SetRotting makes one plant start (true) or stop (false) rotting. The setting is saved with the plant. A plant whose planting failed has a second rot setting that SetRotting(false) does not clear, so that plant keeps rotting. (It sets the plant’s Rotting flag, the flag the growing station’s rot sets on all its plants.)

Planting

  • Plant puts an item in a growing spot that is empty. The item must be one that grows. It gives false when the spot already holds a plant, when the item is not known, or when the item has nothing to grow. (The item needs a prefab with a grow component.)
  • You can only plant in a spot you know the id of. The framework lists a spot only while it holds a plant, so take the SpotId from Growing stations before you empty the spot.

Rules for every call

  • Your mod’s id is checked and used in the log. These calls do not hold a claim on the plant, so two mods can call them without conflict. The last call wins. An invalid mod id throws an error. (ModIds.Require throws an ArgumentException for an id that is not 1 to 64 characters of letters, digits, ., _ or -.)
  • A call gives false while a save is loading or being written. (It checks SaveData.Busy first.)
  • A plant id or spot id that matches nothing gives false.

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. Logs go to BepInEx\logs\obenseuer.moddingframework.plantactions.log.

Everything not listed in this reference is internal and may change without notice.

If something fails to set up

The framework changes some of the game’s methods when it starts, so it can tell your mod when something happens. This part of the API changes none of them and has no events, so there is nothing that can fail to set up. Its name in the log is obenseuer.moddingframework.plantactions. The harvest events are on the Recipes page.

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 works safely on one thread, the main thread (see the glossary).
  • An error from the game is caught and logged once, and you get false. The first error of each call goes to the log. Later errors of that call are not logged again.