Skip to content

AcresFarmRuntime.h#

Acres/Source/Acres/AcresFarmRuntime.h Generated

The live farm: crops, soil water, ruts and the harvester, wired into the Unreal world.

FAcresFarmRuntime connects the pure maths in AcresFarmModel.h to the ACRE map. It reads farm.json and the ACRE rasters from Content/Simulation, finds the planted crop patches in the level, runs the terrain-routed water grid (382 x 382 cells of 4 m, plus a 0.25 m wheel sub-grid where wheels have passed) on its own worker thread, and answers the vehicle's questions: how wet and how rutted is the ground under this wheel, what did this tyre crush, what did the header cut.

Threads: - Physics thread (AcresVehicle's 120 Hz AsyncPhysicsTickActor, Unreal's fixed-step physics callback): calls Advance, Sample, Wheel, Cut, AddMud while holding Mutex. - Game thread (the main thread, where Unreal's per-frame Tick runs): calls Initialize, UpdateVisuals, Status, Replant, Save/Load/Export. - "AcresWater" worker thread: steps the water grid and publishes triple-buffered snapshots that the other threads read without locking (Water()).

Coordinates are Unreal world metres (Unreal itself works in centimetres; callers divide by 100): X east, Y south, Z up, origin at the centre of the 1524 m ACRE tile. Unreal container types used below: TArray (std::vector), TMap (std::unordered_map), TSet (std::unordered_set), FIntPoint (int x, y pair), FString (string), TSharedPtr / TUniquePtr (shared_ptr / unique_ptr), FCriticalSection (a recursive mutex).

FAcresCropProxy#

struct FAcresCropProxy

Snapshot of one crop patch for the LiDAR (sensor-only, never affects forces).

A patch is one authored 1.52 m x 1 m block of plants with 4 x 4 crush/harvest sample bits (see AcresFarm::CropState).

Name Type Unit Default Description
X, Y, Z, HeightM, Growth float X, Y, Z: patch origin in world metres. HeightM: full-grown plant height of the patch mesh, m. Growth: growth fraction 0..1 of the patch's field.
Crushed, Harvested uint16 Crushed, Harvested: 16-bit sample masks, bit (J * 4 + I).
Kind uint8 0 Crop kind (AcresCrops): 0 corn, 1 soybean, 2 potato.

FAcresWorkDetail#

struct FAcresWorkDetail

What one tool pass leaves in the cells it marks (FAcresFarmRuntime::Work), from the implement's physical state: the pawn fills it each step (AcresFieldWorkModel.h has the models). Lateral positions are along the pass's right-hand axis (Unreal Y for a pass heading +X), measured from the strip centre, m.

Name Type Unit Default Description
TillPattern AcresSim::ETillagePattern Tillage: pattern (AcresSim::ETillagePattern; None for the drill and the sprayer), working depth, m, and the seedbed it leaves (ridge, clods, bulking rise, saturation of the turned soil).
ToolSpacingM double m .3 Tine spacing, or the packer's ring spacing for the disc harrow, m.
ToolOriginM double m 0 Lateral position of the first tine or ring, m.
GrooveM double m 0 Packer ring groove depth (the roller's sinkage), m.
RowSpacingM, RowOriginM, PressSinkageM, SowingDepthM double Drill: row spacing, lateral position of the first row, press wheel sinkage and sowing depth, m.
SprayM3M2 double 0 Sprayer: liquid applied, m3/m2.

FAcresBaleRecord#

struct FAcresBaleRecord

A bale left on the field (the square baler's or a round bale the loader put down), for the save.

Name Type Unit Default Description
Kind uint8 0 Kind: 0 round (loader), 1 square (baler).
PositionM FVector m FVector::ZeroVector PositionM: centre, world m. Rotation: orientation. MassKg: bale mass, kg.

FAcresWaterSnapshot#

struct FAcresWaterSnapshot

Published state of the terrain-routed water grid (382 x 382 cells, 4 m).

The water worker thread fills one of three buffers and then flips an index, so readers always see a complete snapshot without taking a lock. Per-cell arrays are row-major, index V * W + U, with the cell origin at -762.0015 m on both axes (same layout as ACRE/field-grid.json).

Name Type Unit Default Description
W int 0 Cells per side (382 in the shipped data; 0 until the first publish).
ClockS double s 0 Water-grid environment time, s.
MaxPondM double m 0 Deepest pond on the grid, m.
MeanPondM double m 0 Mean pond depth over all cells, m.
BacklogS double s 0 Environment seconds requested but not yet simulated (the water lags the game by this much), s.
Theta TArray<float> Surface-layer water content, m3/m3.
PondM TArray<float> m Pond depth, m.
Wetness TArray<float> 0..1, (theta - antecedent) / (saturated - antecedent), clamped; 0 = as dry as at the start, 1 = saturated.
Look TArray<float> Per cell, for the ground's look only (never the tyres): how wet the surface appears, 0..1, the larger of Wetness and the layer's free water above field capacity, (theta - fc) / (saturated - fc). A field that starts saturated looks wet although its Wetness (the change since the start) is 0.
FieldTheta, FieldPond double Mean surface theta (m3/m3) and mean pond depth (m) per field id: 1-59 fields, 60 asphalt, 61 concrete, 62 gravel, 0 everything else.
TotalRainM, TotalPondM, TotalStorageM, TotalEvapM, TotalDrainM, TotalTileM, ResidualM double Grid-mean cumulative ledgers, m of water: rain, current pond, storage change (both layers), evaporation, deep drainage, tile drainage. ResidualM: mean absolute per-cell mass-balance error, m.
bValid bool false False until the first publish; readers fall back to defaults while false.
FineDiv int 0 Wheel sub-grid (AcresFarm::WaterGrid::FineTile), published for the cells wheels have crossed. FineDiv: sub-cells per side of a tile (16, i.e. 0.25 m; 0 before the first publish). Sub-cell K of a tile is K = J * FineDiv + I, I along +X and J along +Y from the cell's corner.
FineCell TArray<int32> Parent cell index of each published tile, ascending (FineIndex binary-searches it).
FineLevel TArray<float> Pond water level relative to the unrutted bed, m; the local pond depth over a sub-cell with rut depth r is max(0, level + r), and those depths average to the cell's PondM exactly.
FineWetScale TArray<float> 1 / (saturated - antecedent theta), turns a theta anomaly into a wetness anomaly.
FineTheta TArray<float> Per tile, FineDiv * FineDiv surface theta anomalies relative to the cell's Theta, m3/m3 (zero mean per tile), tile after tile in FineCell order.

FAcresWaterSnapshot::FineIndex#

Published tile of a cell.

Argument Description
Cell Cell index, V * W + U.

Returns: Index into FineCell (and FineLevel, FineWetScale, FineTheta / FineDiv^2), or -1 without a tile.

int FineIndex(int Cell) const;

FAcresWaterSnapshot::LevelAt#

Water level of a cell relative to its unrutted bed, m: the tile's FineLevel, or PondM without a tile.

Argument Description
Cell Cell index, V * W + U.

Returns: Level, m (negative when the cell's water stands only in its ruts).

double LevelAt(int Cell) const;

FAcresFarmRuntime#

class FAcresFarmRuntime

Farm state shared by the tractor and its trailer: crops, soil water, ruts, harvester and bunker.

AAcresVehiclePawn creates one with MakeShared, calls Initialize() on the game thread at BeginPlay (the callback Unreal runs when an actor enters the world), then drives it every physics step. All numeric methods and public fields need Mutex held; only Initialize and UpdateVisuals touch Unreal objects (UObjects, the garbage-collected engine objects), and only on the game thread. The water grid advances on its own worker thread and publishes snapshots; Water() reads them lock-free.

Command-line switches read by Initialize (Unreal passes "-Name=value" arguments): -FarmRain=, -FarmTimeScale=, -FarmMinC=, -FarmMaxC=, -FarmEvap=, -FarmHarvester, -FarmHarvestOn, -FarmInitialTheta=, -FarmKsatScale=, -FarmInitialGrowth=, -FarmLoad=, -FarmPreDays=, -nullrhi (no rendering, so no visuals).

Example

Farm = MakeShared<FAcresFarmRuntime>();
Farm->Initialize(GetWorld(), 20, 12); // 20 mm of rain over the 12 h before start
// physics thread, every 1/120 s:
FScopeLock Lock(&Farm->Mutex);
Farm->Advance(Dt);
Farm->Sample(ContactM.X, ContactM.Y, Surface);
Name Type Unit Default Description
Mutex FCriticalSection Guards every field and method below except Water(). FScopeLock L(&Mutex) holds it for a scope.
SessionYear, SessionMonth, SessionDay int Local date of the session (the environment clock), set before Initialize: -CropStage=date grows each field of the crop season from its planting date to this day. 0 = unknown.
bLoadedAtStart bool false True when the farm began from a saved state (-FarmLoad=, or a replayed session's farm-start-state.json); the pawn then writes that start state into the new session's folder, so a replay of this session starts the same way.
WorkTilled, WorkSeeded, WorkSprayed static constexpr uint8 Field work flag bits in Worked.
Worked TMap&lt;FIntPoint, uint8> Field work per 25 cm cell (same keys as Ruts): WorkTilled / WorkSeeded / WorkSprayed bits. They last for the simulation (RL and R-key resets keep them), are saved by Save and restored by Load; only RestoreField (an RL reset that asks for it) clears a field's marks.
double WorkedM2[3][60] = {}; double WorkedM2[3][60] Area marked per field bucket (0 outside fields, 1..59 fields), m2: [0] tilled, [1] seeded, [2] sprayed. Written to farm-fields.csv.
FieldCells TMap&lt;FIntPoint, FAcresFieldCell> What field work left in each 25 cm cell (same keys as Ruts): the visible trace of tillage, drilling, spraying, tyre prints and backhoe spoil, drawn by FAcresSoilVisuals. Saved and restored with the session (schema 4).
Relief TMap&lt;FIntPoint, float> Pits (negative) and spoil (positive) relative to the original surface per 25 cm cell, m (Dig, Spoil, ReliefAt).
Bales TArray&lt;FAcresBaleRecord> Bales on the field, written by the pawns that own them before a save (the pawns' physics bodies are the live state); a loaded save's bales are spawned again by the pawn.
Ruts TMap&lt;FIntPoint, double> Rut depth per 25 cm cell, m, keyed by (floor(X / 0.25 m), floor(Y / 0.25 m)). Wheels and the backhoe only deepen them and tillage (Work) levels them; they persist for the session and are saved.
HasHarvester bool false Header fitted (-FarmHarvester).
HarvestEnabled bool false Header switched on (H key or -FarmHarvestOn).
bDigger bool false True when the harvester is the potato digger: it lifts only potato; the grain cutter skips potato.
TimeScale double 1 Environment seconds per game second.
RainMmH double 0 Rain rate, mm/h. MinC,
MinC double °C 16 See above.
MaxC double °C 28 Daily minimum and maximum temperature, deg C.
EvapMmDay double 2 Potential evaporation, mm/day. AcresVehicle overwrites these from the environment model every physics step when one exists.
SurfaceFilm double 0 Rain film on the ground surface, 0..1 (AcresEnv::State::SurfaceWetness: the weather model's 0.3 mm interception store over its capacity). Set by AcresVehicle with the weather above; Sample uses it on soil.
ClockS double s 0 Farm environment time since start, s.
HarvestKg double kg 0 Total grain harvested, kg.
BunkerKg double kg 0 Grain in the bunker now, kg.
UnloadedKg double kg 0 Grain unloaded so far, kg (HarvestKg = BunkerKg + UnloadedKg).
CrushedM2 double 0 Crop area crushed by wheels, m2.
HeaderWidthM double m 3 Cut width, m. HeaderOffsetXM,
HeaderOffsetXM double -3.2 See above.
HeaderOffsetYM double 2.5 Header centre relative to the tractor in its local frame, m.
HeaderPtoKW double kW 35 Power the header draws from the PTO, kW.
BunkerCapacityKg double kg 600 Bunker size, kg.
bLogEvents bool false Episode-log capture: while bLogEvents is set, Stamp (crop), Wheel (ruts, in 5 mm steps), Work (new flags) and RestoreFieldId append what they changed to LogEvents, tagged with LogStepKey and LogAgent, which each pawn sets when it takes Mutex for its physics step. Mutex held for all of them.
LogStamps TArray&lt;FLogStamp> Wheel and Body calls while bLogEvents is set; LogWheel is the wheel index the pawn sets before each Wheel call.

FAcresFarmRuntime::~FAcresFarmRuntime#

Stops and joins the water worker thread.

~FAcresFarmRuntime();

FAcresFarmRuntime::Initialize#

Load the farm and start the water thread. Game thread only, once.

Reads farm.json, ACRE/field-grid.json, field_ids.u8, cover.u8, soil_units.u8, soils.json and heights.f32 (crashes via check() if any is missing or malformed), applies command-line overrides and the menu's field setup (soil overrides, starting wetness, crop swaps, terrain edits), builds the water grid, replaces each crop HISM (hierarchical instanced static mesh: one component drawing thousands of copies of one mesh) with a movable ISM so patches can be squashed individually, optionally loads a save (-FarmLoad=), pre-runs -FarmPreDays= days and the prior rain, then starts the worker and the soil visuals.

Argument Description
World The level holding the ACRE crop actors (tagged with a crop name, "corn"/"soybean"/"potato", and "Fxx").
PriorRainMm Rain assumed to have fallen before the start, mm. 0 skips the pre-run.
PriorRainHours Hours over which PriorRainMm is spread evenly, h.

Note

The pre-runs advance ClockS and crop degree days too; the session starts after them.

void Initialize(UWorld* World, double PriorRainMm = 0, double PriorRainHours = 12);

FAcresFarmRuntime::Advance#

Advance farm time by one physics step. Physics thread, Mutex held.

Scales Dt by TimeScale into environment seconds, hands them to the water thread, and grows crops in 10 s environment chunks: degree days times a water-stress factor from the field's mean theta and ponding. Appends an hourly row to the weather timeline.

Argument Description
PhysicsDt Physics step, s of game time.
void Advance(double PhysicsDt);

FAcresFarmRuntime::Sample#

Fill the soil-water and rut fields of a wheel's surface sample. Physics thread, Mutex held.

Resolved at the tyre's scale, not the 4 m cell's: the cell fields are interpolated bilinearly between the four nearest cell centres (soil cells only, for theta and wetness), then the 0.25 m wheel sub-grid adds its detail where wheels have passed. WaterDepthM is the local pond depth, max(0, level + rut depth), so water stands in a rut and not on the ridge beside it when the cell's pond fits in its ruts. On soil (Surface.Soil true) Theta and Wetness add the sub-grid's moisture anomaly (bilinear between 0.25 m sub-cell centres: wet rut bottoms, drier compacted tracks), and RutDepthM comes from the 25 cm rut map. On soil Wetness is also at least the rain film (SurfaceFilm) and the local pond depth over 2 mm: the raindrop-wetted or ponded surface slicks the tread-soil interface before the 0.3 m layer's theta has risen (Wong 2008 Table 1.3, dry against wet earth). On a hard surface Wetness is the pond depth over 2 mm, clamped to 1. Water values are untouched outside the grid or before the first snapshot.

Argument Description
X World X, m.
Y World Y, m.
Surface Wheel input, updated in place. Soil must already be set by the caller.
void Sample(double X, double Y, AcresSim::FVehicleInput& Surface) const;

FAcresFarmRuntime::Wheel#

Apply one tyre contact: crush crops, deepen ruts, compact soil. Physics thread, Mutex held.

Crops under the Width x Length rectangle are crushed if the contact pressure exceeds 10 kPa and the field is past 2 % growth. With Sinkage > 0 the 25 cm rut cells under the footprint deepen to min(0.35 m, 0.65 * Sinkage) (never shallower). Each deepened rut cell is sent to the water grid's wheel sub-grid with its rut depth and compaction min(1, rut / 0.065 m) (= min(1, Sinkage / 0.1 m)), so the 4 m cell's infiltration drops by the compacted share of its area and its ruts store ponded water.

Argument Description
X Contact point X, m.
Y Contact point Y, m.
Z Contact point Z, m (patches more than 1 m above or below are ignored).
ForwardX X component of the unit heading along the ground.
ForwardY Y component of the unit heading along the ground.
Width Footprint width across travel, m.
Length Footprint length along travel, m.
Pressure Mean contact pressure, Pa.
Sinkage Tyre sinkage, m (0 on hard surfaces).
TyreDiameterM Tyre diameter, m; with more than 5 mm of sinkage the footprint's cells also record the tread print (AcresSim::TreadPrintDepthM, lug pitch, heading and each cell's place across the tyre). 0 leaves no print.
void Wheel(double X, double Y, double Z, double ForwardX, double ForwardY, double Width, double Length, double Pressure, double Sinkage, double TyreDiameterM = 0);

FAcresFarmRuntime::Body#

Push over the crop the machine's body and front axle ride through. Physics thread, Mutex held.

Tyres crush only their own tracks (Wheel); a tractor driven through corn also bends every stalk taller than the underbody across its full width. Plants shorter than ClearanceM pass under the body (soybean, potato, young corn) and are left alone.

Argument Description
Width Body width across travel, m (outer tyre edge to outer tyre edge).
Length Footprint length along travel this step, m (body length plus distance moved).
ClearanceM Underbody / front axle clearance, m.
void Body(double X, double Y, double Z, double ForwardX, double ForwardY, double Width, double Length, double ClearanceM);

FAcresFarmRuntime::Cut#

Run the harvester header over the crop. Physics thread, Mutex held.

Does nothing unless a harvester is fitted and switched on, engine speed is at least 1200 rpm, ground speed is 0.05-4 m/s and the bunker has room. Otherwise harvests mature samples under a HeaderWidthM x 0.8 m rectangle into the bunker.

Argument Description
X Header centre X, m.
Y Header centre Y, m.
Z Header centre Z, m.
ForwardX X component of the tractor heading.
ForwardY Y component of the tractor heading.
Speed Forward ground speed, m/s.
Rpm Engine speed, rev/min.

Returns: Grain added to the bunker this call, kg.

double Cut(double X, double Y, double Z, double ForwardX, double ForwardY, double Speed, double Rpm);

FAcresFarmRuntime::UpdateVisuals#

Push crop, rut, water and mud changes to the renderer. Game thread; takes Mutex itself.

Copies the rut map, dirty rut tiles and queued mud under the lock, ticks FAcresSoilVisuals outside it, then rescales at most 1024 changed crop instances per call (the rest wait for the next frame; all of them under simulator control, so lockstep sensor samples do not depend on the frame count).

Argument Description
PhysicsTime Current simulation time, s (used for the visual time step, capped at 0.1 s).
VehicleM Tractor position in world metres (tiles and effects are built around it).
void UpdateVisuals(double PhysicsTime, const FVector& VehicleM);

FAcresFarmRuntime::ReleaseVisuals#

Drop the soil visuals (and the material instances they keep alive). Game thread; takes Mutex itself.

Call from EndPlay: the visuals hold strong references into the world, and the owning pawn is only destroyed after the garbage collection that must free the old world on a level change.

void ReleaseVisuals() ;

FAcresFarmRuntime::AddMud#

Queue one cosmetic particle (mud clod, dust puff or water drop) for the next UpdateVisuals. Physics thread, Mutex held.

Ignored when there are no visuals (-nullrhi) or 512 particles are already queued.

Argument Description
Spawn Kind, launch position (m) and velocity (m/s) of the particle.
void AddMud(const FAcresMudSpawn& Spawn) ;

FAcresFarmRuntime::Save#

Write farm state to a JSON file plus a binary water sidecar in the same folder, named after the file with "state" replaced by "water" (farm-state.json -> farm-water.bin, farm-start-state.json -> farm-start-water.bin).

Game thread, Mutex held. Schema 3: fingerprint of the farm inputs, 11 scalar states, 60 GDD values, per-patch masks, ruts (with backhoe pits), field work marks (tilled / seeded / sprayed cells and areas; schema 2 saves lack them and load with none), harvest switch, and 11 float64 arrays of water state (the 11th, edge runoff, was added later; older saves have 10). The wheel sub-grid is not stored separately: its rut depths and compaction are rebuilt from the saved ruts on Load (compaction is a function of rut depth), and its moisture anomaly restarts at 0 (it is zero-sum within each cell, so no water is lost).

Argument Description
Path Destination JSON path; written through a temp file and renamed.

Returns: True if both files were written.

bool Save(const FString& Path);

FAcresFarmRuntime::Load#

Restore state written by Save(). Game thread, Mutex held.

Validates the schema, input fingerprint, every value's range and the sidecar hash before changing anything; a failed load leaves the farm untouched. Accepts water sidecars with 11 arrays and older ones with 10, for which the edge-runoff ledger is rebuilt from each cell's water balance. Rebuilds the wheel sub-grid from the loaded ruts; whole-cell compaction from older saves is kept as a floor.

Argument Description
Path JSON path written by Save().

Returns: False if the file is missing, from a different farm setup, or out of range.

bool Load(const FString& Path);

FAcresFarmRuntime::Export#

Save state and write reports: farm-state.json, farm-fields.csv, farm-events.csv, farm-weather.csv, farm-water.json, water-depth.f32, theta.f32, farm-visuals.json and a copy of farm.json.

Game thread, Mutex held.

Argument Description
Directory Output folder (created if needed).
void Export(const FString& Directory);

FAcresFarmRuntime::Status#

One-line HUD text for the field under a point: growth, theta, pond, rain, time scale, day, water lag, cutter and bunker.

Argument Description
X World X, m.
Y World Y, m.

Returns: Human-readable status line.

FString Status(double X, double Y) const;

FAcresFarmRuntime::Replant#

Reset the field under a point: clear every patch mask and restart its degree days at 0.

Argument Description
X World X, m.
Y World Y, m.
void Replant(double X, double Y);

FAcresFarmRuntime::RestoreField#

Undo the machine's marks on the field under a point, keeping the crop's growth: clear every patch's crushed and harvested masks and the field's ruts, and rebuild the water grid's wheel sub-grid from the ruts left elsewhere (as Load does). Used by the RL bridge so each episode starts on an untouched field. Call with Mutex held.

Argument Description
X World X, m.
Y World Y, m.

Returns: The field id, or 0 when the point is not in a field.

int RestoreField(double X, double Y);

FAcresFarmRuntime::FieldAt#

Field id under a point from the 4 m field raster.

Argument Description
X World X, m.
Y World Y, m.

Returns: 1-59 for a field, 0 outside fields or outside the grid.

int FieldAt(double X, double Y) const;

FAcresFarmRuntime::SnapshotCropProxies#

Append every crop patch within RadiusM + 1.5 m of (X, Y) to Out. Mutex must be held by the caller.

Argument Description
X Centre X, m.
Y Centre Y, m.
RadiusM Search radius, m.
Out Receives the patches (appended, not cleared).
void SnapshotCropProxies(double X, double Y, double RadiusM, TArray<FAcresCropProxy>& Out) const;

FAcresFarmRuntime::Water#

Latest water snapshot, lock-free (triple buffered). Any thread.

Returns: The most recently published snapshot, or an empty one (bValid false) before Initialize.

Note

The reference stays valid for two further publishes (at least ~0.4 s of wall time). Copy what you need rather than holding it across frames.

const FAcresWaterSnapshot& Water() const;

FAcresFarmRuntime::Work#

Mark field work on a rectangle of 25 cm cells (the rut map's cells). Physics thread, Mutex held.

Tillage (WorkTilled) loosens the soil: the vehicle then evaluates tyres and implements on these cells at the soil class's loose density (AcresSim::FSoilClass::LooseDensity), so the next pass sinks further, grips less and a second tillage pass pulls less. It also levels the surface: rut depths and tread prints under the strip are cleared (their render tiles redrawn), while the water grid's wheel sub-grid keeps the compaction it recorded (the subsoil below tillage depth stays compacted); earlier drill rows are buried. WorkSeeded and WorkSprayed record coverage. With Detail, every cell also records what the pass left for the visuals (FAcresFieldCell: the latest pass wins): the seedbed and the tool phase across the implement, the drill rows and the field's degree days at sowing, the spray rate and the farm clock.

Argument Description
Width Worked width across travel, m.
Length Strip length along travel, m (distance moved this step plus a margin).
Flags WorkTilled, WorkSeeded and/or WorkSprayed.
Detail What the tools left (may be null: coverage only).
void Work(double X, double Y, double ForwardX, double ForwardY, double Width, double Length, uint8 Flags, const FAcresWorkDetail* Detail = nullptr);

FAcresFarmRuntime::WorkedAt#

Work flags of the 25 cm cell under a point (0 when untouched). Any thread holding Mutex.

uint8 WorkedAt(double X, double Y) const ;

FAcresFarmRuntime::Dig#

Dig a pit (backhoe bucket): the relief of the 25 cm cells under the rectangle is lowered evenly by VolumeM3, but not below -MaxDepthM (nor 1.2 m below the original surface). The relief is part of the ground the vehicles stand on (ReliefAt: wheel contacts and implement ground traces follow it), is drawn by the rut tiles and stores ponded water like a rut. Physics thread, Mutex held.

Argument Description
VolumeM3 Soil removed this call, m3 (in place).
MaxDepthM Deepest floor, below the original surface, m (the bucket tip).
Look Clod size and saturation of the exposed soil (Surface of a AcresSim::ETillagePattern::Spoil pass).
void Dig(double X, double Y, double ForwardX, double ForwardY, double Width, double Length, double VolumeM3, double MaxDepthM, const AcresSim::FTillageSurface& Look = ;);

FAcresFarmRuntime::Spoil#

Dump spoil (backhoe bucket): the loose volume joins the nearest pile within 1.2 m (or starts one) and the pile is laid out as a cone at the angle of repose (35 deg; AcresSim::SpoilConeRadiusM), raising the relief (pit cells under a wide cone stay open). Physics thread, Mutex held.

Argument Description
VolumeM3 Loose volume dumped, m3 (AcresSim::SpoilVolumeM3).
Look Clod size and saturation of the spoil.
void Spoil(double X, double Y, double VolumeM3, const AcresSim::FTillageSurface& Look);

FAcresFarmRuntime::ReliefAt#

Height of the dug and heaped ground relative to the original surface at a point, m (pits negative, spoil positive), bilinear between 25 cm cell centres; 0 where nothing was dug. Any thread holding Mutex.

double ReliefAt(double X, double Y) const;

FAcresFarmRuntime::AvailableWaterAt#

Plant-available water of the surface layer at a point: (theta - wilting point) / (field capacity - wilting point) of the 4 m cell's mapped soil unit, clamped to 0..1.3 (-1 outside the grid, on pavement or before the first snapshot). Any thread.

double AvailableWaterAt(double X, double Y) const;

FAcresFarmRuntime::ReliefVolumes#

Total volume of the pits (below the original surface) and of the spoil piles (above it), m3.

void ReliefVolumes(double& PitM3, double& SpoilM3) const;

FAcresFarmRuntime::RestoreFieldId#

Clears one field's marks and crop damage, as RestoreField does for the field under a point. Mutex held.

Returns: The field id, or 0 when the id is out of range.

int RestoreFieldId(int Field);

FAcresFarmRuntime::ApplyLogEvent#

Replays one logged farm event (episode-log replay): sets the crop sample bits, work flags or rut depth it recorded (the look of field work falls back to plain marks), or restores the field. Mutex held.

Argument Description
EventKind FLogEvent kind. PatchIndex, Samples: crop events. Flags: work flags. X, Y: Unreal world m.
Value rut depth, m. Field: field id (field restored).
void ApplyLogEvent(uint8 EventKind, int PatchIndex, uint16 Samples, uint8 Flags, double X, double Y, double Value, int Field);

FAcresFarmRuntime::FieldStats#

Per-field ground truth for task scoring, fields 1-59. Crushed crop is split at the allowed band: a crushed sample (1/16 of a 1.52 m2 patch) counts as in the band when EdgeDistanceM(field, x, y) <= EdgeBandM (Unreal world m). Mutex held.

void FieldStats(double EdgeBandM, TFunctionRef<double(int, double, double)> EdgeDistanceM, TArray<FFieldStats>& Out) const;

FAcresFarmRuntime::QueryPoint#

Fills Out for a point, Unreal world m. Mutex held.

void QueryPoint(double X, double Y, FPointInfo& Out) const;

FAcresFarmRuntime::SetSoilWetness#

Sets the surface-layer water content of the soil cells of some fields: theta = wilting point + Wetness x (saturated - wilting point) of each cell's water unit (pavement and gravel keep theirs). Takes the water grid's lock and publishes a snapshot. Any thread.

Returns: The number of cells changed.

int SetSoilWetness(const TArray<int>& Fields, double Wetness);

FAcresFarmRuntime::SetDeterministicWater#

Lockstep (AcresSimControl.h): on, the water grid is stepped and published by Advance on the physics thread at fixed simulation times (10 s grid steps, a snapshot every 0.5 s) instead of by the worker on wall-clock time, so the same commands give the same soil under the tyres; off hands the grid back to the worker. Game thread.

void SetDeterministicWater(bool bOn);

FSpoilPile#

struct FSpoilPile

Spoil piles: centre (world m) and loose volume (m3).

FLogEvent#

struct FLogEvent

One farm change for the episode log. Kind: 1 crop crushed, 2 crop harvested, 3 cell worked, 4 rut deepened, 5 field restored (AcresLog::FFarmEvent). Agent: agent index (-1 unknown). Field: field id. Patch: crop patch index (-1 for cells). Samples: the patch's newly set 4 x 4 sample bits. Flags: newly set work flags. X, Y: patch origin or cell centre, Unreal world m (Y south). Value: area, m2, or rut depth, m. StepKey: world time x 120.

FLogStamp#

struct FLogStamp

One Wheel (Kind 0) or Body (Kind 1) call for the episode log (acres_interfaces/FarmStamp): its arguments (Unreal world m, Y south), the wheel index (-1 for the body), the crop it crushed, m2, and the tags as above.

FFieldStats#

struct FFieldStats

Ground truth of one field (acres_interfaces/FieldState). Areas in m2; ThetaMean m3/m3 (-1 without soil cells); PondMeanM m.

FPointInfo#

struct FPointInfo

Ground truth at one point (acres_interfaces/FieldQuery).