Skip to content

ItemFarmAsset — Farm Barricade Definition

Overview

ItemFarmAsset extends ItemBarricadeAsset with crop growth and harvesting mechanics. It defines plantable barricades that go through growth stages (seedling → growing → mature → ready), can be harvested for items, and are affected by rain, fertilizer, and the Agriculture player skill. The class supports both legacy item IDs and modern spawn tables for harvest rewards.

Farm barricades use EBuild.FARM with a 4-byte state storing the Unix timestamp of when the crop was planted. Growth progress is calculated as elapsed time divided by the Growth duration. Visual states transition at 33% and 66% progress thresholds.

Source code location: Unturned/Bundles/ItemFarmAsset.cs (150 lines), inheriting from ItemBarricadeAsset.cs (605 lines), ItemPlaceableAsset.cs (454 lines), and ItemAsset.cs (base).

Inheritance Chain

ItemAsset → IArmorFalloff
  └─ ItemPlaceableAsset — salvage, destroy drops, crafting tags, armor falloff
       └─ ItemBarricadeAsset — EBuild system, placement, health
            └─ ItemFarmAsset — growth, harvest, skill integration

Class Definition

csharp
public class ItemFarmAsset : ItemBarricadeAsset
{
    protected uint _growth;
    protected ushort _grow;
    public System.Guid growSpawnTableGuid;

    public uint growth => _growth;
    public ushort grow => _grow;

    public bool ignoreSoilRestrictions { get; protected set; }
    public bool canFertilize { get; protected set; }
    public uint harvestRewardExperience;
    public bool isAffectedByAgricultureSkill { get; protected set; }
    public bool shouldRainAffectGrowth { get; protected set; }

    internal NPCRewardsList harvestRewardsList;

    public override void BuildDescription(ItemDescriptionBuilder builder, Item itemInstance) { ... }
    public override void PopulateAsset(in PopulateAssetParameters p) { ... }
    internal override void BuildCargoData(CargoBuilder builder) { ... }
}

Growth System

Growth Duration

.dat KeyTypeDefaultUnit
GrowthuintRequiredSeconds for full growth
csharp
_growth = p.data.ParseUInt32("Growth");

The growth duration in seconds. A value of 600 means the crop takes 10 minutes to fully grow. No default — the key is required for the farm to function.

Growth Calculation

csharp
uint plantedTime = BitConverter.ToUInt32(instance.state, 0);
uint currentTime = Provider.time;
uint elapsedSeconds = currentTime - plantedTime;
float growthPercent = Mathf.Clamp01((float)elapsedSeconds / growth);

The 4-byte FARM state stores Provider.time at planting. Growth progress is the ratio of elapsed time to total growth duration.

Growth Stages

ProgressVisual StateInteraction
0–33%SeedlingCannot harvest
33–66%GrowingCannot harvest
66–99%MatureCannot harvest
100%ReadyCan harvest

The visual state transitions are handled by the interactable farm system based on growthPercent thresholds.


Harvest System

Legacy Grow ID

.dat KeyTypePurpose
GrowushortLegacy item ID of harvest result
csharp
_grow = p.data.ParseUInt16("Grow");

The legacy harvest item ID. This is the older system — Grow_SpawnTable takes priority if both are set.

Grow Spawn Table

.dat KeyTypePurpose
Grow_SpawnTableGUIDSpawn table for harvest result
csharp
growSpawnTableGuid = p.data.ParseGuid("Grow_SpawnTable");

The modern harvest system uses a spawn table GUID. When set, the farm resolves a random item from the spawn table on harvest. This enables loot-table-style farming where different items can drop from the same crop.

Priority

If Grow_SpawnTable is set, it takes priority over the legacy Grow ID. If neither is set, the farm produces nothing on harvest.

Description Display

csharp
if (grow != 0)
{
    ItemAsset growAsset = Assets.find(EAssetType.ITEM, grow) as ItemAsset;
    if (growAsset != null)
    {
        builder.Append(localization.format("ItemDescription_Farmable_GrowSpecificItem",
            "<color=" + Palette.hex(ItemTool.getRarityColorUI(growAsset.rarity)) + ">"
            + growAsset.itemName + "</color>"), DescSort_Important);
    }
}

The legacy harvest item is shown in the tooltip with its rarity-colored name. Spawn table harvests are not displayed in the tooltip — only the legacy Grow ID triggers a tooltip line.


Rain Growth Acceleration

csharp
shouldRainAffectGrowth = p.data.ParseBool("Rain_Affects_Growth", defaultValue: true);
.dat KeyTypeDefaultEffect
Rain_Affects_GrowthbooltrueRain speeds up crop growth

When raining, the effective growth time is reduced: growth /= 1 + rainIntensity. Heavier rain causes faster growth. This simulates real-world farming where rainwater accelerates plant growth.

When false, rain has no effect — the crop grows at the base rate regardless of weather.


Agriculture Skill Integration

csharp
isAffectedByAgricultureSkill = p.data.ParseBool("Affected_By_Agriculture_Skill", defaultValue: true);
.dat KeyTypeDefaultEffect
Affected_By_Agriculture_SkillbooltrueAgriculture skill provides bonus

When true, the player's Agriculture skill level reduces growth time: growth *= (1 - skillLevel * config.reductionPerLevel). Higher skill = faster growth. The skill also provides a chance for a second harvest item.

When false, the Agriculture skill has no effect.


Fertilizer Support

csharp
canFertilize = p.data.ParseBool("Allow_Fertilizer", defaultValue: true);
.dat KeyTypeDefaultEffect
Allow_FertilizerbooltrueFertilizer items can be applied

When true, players can use fertilizer items on the farm to accelerate growth. When false, fertilizer cannot be applied.


Soil Restrictions

csharp
ignoreSoilRestrictions = p.data.ContainsKey("Ignore_Soil_Restrictions");
.dat KeyTypeDefaultEffect
Ignore_Soil_RestrictionsflagBypasses soil requirement

By default, farms require soil (plantable terrain). Setting Ignore_Soil_Restrictions allows planting on any surface. This is common in modded farms that use planters, hydroponics, or grow-beds that provide their own growing medium.

Tooltip note: The description only shows the "Requires Soil" line when ignoreSoilRestrictions is false — the restriction is shown rather than the bypass, as requiring soil is the vanilla default.


Harvest Reward Experience

csharp
harvestRewardExperience = p.data.ParseUInt32("Harvest_Reward_Experience", defaultValue: 1);
.dat KeyTypeDefaultEffect
Harvest_Reward_Experienceuint1XP granted on successful harvest

Harvest Rewards (NPC Quest System)

csharp
harvestRewardsList.Parse(p.data, p.localization, this, "Harvest_Rewards", "Harvest_Reward_");

Farms can grant NPC-style rewards when harvested. This internal system allows quest-like reward triggers on crop harvest. The reward list is parsed from the .dat using the same infrastructure as NPC quest rewards.


BuildDescription — Inventory Tooltip

csharp
public override void BuildDescription(ItemDescriptionBuilder builder, Item itemInstance)
{
    base.BuildDescription(builder, itemInstance);

    if (grow != 0) { /* show harvest item with rarity color */ }

    builder.stringBuilder.Clear();

    if (!ignoreSoilRestrictions)
        builder.stringBuilder.Append("Requires Soil");

    if (canFertilize)
    {
        if (builder.stringBuilder.Length > 0) builder.stringBuilder.Append(' ');
        builder.stringBuilder.Append("Can be Fertilized");
    }

    if (isAffectedByAgricultureSkill)
    {
        if (builder.stringBuilder.Length > 0) builder.stringBuilder.Append(' ');
        builder.stringBuilder.Append("Affected by Agriculture Skill");
    }

    if (shouldRainAffectGrowth)
    {
        if (builder.stringBuilder.Length > 0) builder.stringBuilder.Append(' ');
        builder.stringBuilder.Append("Affected by Rain");
    }

    if (builder.stringBuilder.Length > 0)
        builder.Append(builder.stringBuilder.ToString(), DescSort_FarmableText);
}

The description groups the soil/fertilizer/skill/rain flags into a single paragraph using string concatenation. This is a unique pattern — most other assets use separate builder lines.


BuildCargoData — Wiki Export

csharp
CargoDeclaration data = builder.GetOrAddDeclaration("Farm");
data.Append("GUID", GUID);
data.Append("Growth", growth);
data.Append("Grow", grow);
data.Append("Grow_SpawnTable", growSpawnTableGuid);
data.Append("Ignore_Soil_Restrictions", ignoreSoilRestrictions);
data.Append("Allow_Fertilizer", canFertilize);
data.Append("Harvest_Reward_Experience", harvestRewardExperience);
data.Append("Affected_By_Agriculture_Skill", isAffectedByAgricultureSkill);
data.Append("Rain_Affects_Growth", shouldRainAffectGrowth);

.dat File Reference — Farm-Specific

.dat KeyTypeDefaultNotes
GrowthuintRequiredSeconds for full growth
GrowushortLegacy harvest item ID
Grow_SpawnTableGUIDSpawn table for harvest (takes priority over Grow)
Ignore_Soil_RestrictionsflagNo soil required
Allow_FertilizerbooltrueFertilizer accepted
Harvest_Reward_Experienceuint1XP on harvest
Affected_By_Agriculture_SkillbooltrueSkill bonus applies
Rain_Affects_GrowthbooltrueRain accelerates growth
Harvest_Rewards / Harvest_Reward_NPC rewardsNPC reward triggers on harvest

Modding Example — Basic Tomato Plant .dat

ini
GUID a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
Type Barricade
Build Farm
Health 10
Range 4
Radius 0.3
Offset 0.05
Growth 600
Grow 12345
Harvest_Reward_Experience 5

10-minute growth, harvests item ID 12345, 5 XP per harvest.


Modding Example — Spawn Table Crop .dat

ini
GUID f1e2d3c4b5a69788796a5b4c3d2e1f0a
Type Barricade
Build Farm
Health 10
Range 4
Growth 300
Grow_SpawnTable abc-def-ghi-123
Allow_Fertilizer true

5-minute growth, uses spawn table for random harvest (ignores legacy Grow), accepts fertilizer.


Modding Example — Hydroponic Planter .dat

ini
GUID d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
Type Barricade
Build Farm
Health 50
Range 4
Growth 240
Grow 54321
Ignore_Soil_Restrictions
Affected_By_Agriculture_Skill false
Rain_Affects_Growth false

4-minute growth, no soil required (self-contained planter), skill and rain disabled (controlled environment).


Common Issues

  1. Farm produces nothing: Ensure either Grow (legacy ID) or Grow_SpawnTable (GUID) is set. If Grow_SpawnTable is set, it takes priority. If neither is set, harvest produces nothing.

  2. Growth too fast/slow: Growth is in seconds. A common mistake is using minutes or ticks. 600 = 10 minutes. Use a calculator to verify.

  3. No growth progress: The farm state stores Provider.time at planting. If the farm was placed in a save file with a future timestamp, progress may never reach 100%.

  4. Soil restriction blocking placement: The default requires plantable terrain (soil). Use Ignore_Soil_Restrictions to bypass this for modded planters.

  5. Rain not affecting growth: Rain_Affects_Growth defaults to true. If it's not working, verify the weather system is producing rain in the current map zone.

Document history

VersionDateAuthorNotes
1.02026-07-2857 StudiosInitial publication. Full farm asset documentation including growth system, harvest mechanics, skill integration, and modding examples.