Files
fs25-adsmartpickup/docs/superpowers/specs/2026-09-27-marksilo-flow-design.md
T

6.1 KiB
Raw Blame History

Marksilo-flow — design

Dato: 2026-09-27 · Status: godkendt i chat, afventer review af denne spec

Formål

Høsten lægges ofte i siloer ude ved markerne (mellemlager). I dag skal spilleren selv huske at køre varerne hjem. Marksilo-flowet kigger jævnligt alle marksiloer igennem og sender selv op til x ledige vogne ud for at hente varerne hjem til gårdens lagre.

Succes: står der varer i en marksilo, som gården kan tage, bliver de kørt hjem uden at spilleren gør noget, med højst x vogne ude ad gangen, og uden at tage vogne fra markarbejde, andre flows eller spilleren.

Brugerens valg (fra brainstorm)

Spørgsmål Valg
Hvor er "hjem"? Nærmeste af de gårdlagre, spilleren vælger i flowet, der tager varen og har plads
Hvad er "x vogne"? Lånte ledige vogne fra hele gården — ingen fast tilknytning — højst x ude samtidig
Hvilke vogne må lånes? Samme regel og flueben som markarbejdet (fleetMode "all"/"ticked", ADFieldJobs.state.fleet)

Begreber

  • Marksilo: bygning af typen silo inden for ADFields.FIELD_SILO_DISTANCE (150 m) af en marks polygon (ADFields.fieldSilos), samlet over alle marker, uden dubletter. En bygning, der er valgt som gårdlager i flowet, er aldrig marksilo.
  • Gårdlager: bygning spilleren vælger i flowet (samme bygningsvælger som udkørslens lagre, storeBuildings).
  • Lån: en vogn, flowet har sendt på én tur. Lån ligger kun i hukommelsen.

Flowet

Ny run-type fieldSilos i ADRuns.KINDS (ved siden af supply/outbound). Højst ét marksilo-flow pr. savegame (GUI'et tilbyder ikke at oprette et til, når det findes).

Felter (gemmes i ADSmartPickup_runs.xml som de øvrige):

  • storeBuildings — gårdlagre (bygnings-id'er → markører via den eksisterende resolveMarkers)
  • maxVehicles — x, 1–10, standard 2
  • minLiters — tærskel pr. silo og vare, standard 10000
  • running — til/fra (som de andre flows' Start/Stop)

Planlægning (ren logik, nyt modul adFieldSiloPlanner.lua, testes med luajit)

Input: marksiloer {id, markerId|nil, stock = {[fillType] = liters}}, gårdlagre {id, markerId, accepts = {[fillType] = freeLiters}, x, z}, aktive lån {siloId, fillType, liters}, ledige vogne {id, x, z, capacity, carries = {[fillType] = true}}, maxVehicles, minLiters.

  1. Kvalificerede opgaver: pr. (silo, vare) hvor silo har markør, liters >= minLiters, og mindst ét gårdlager har freeLiters >= minLiters for varen. Resten = liters minus det aktive lån på samme (silo, vare) allerede er på vej med; kun opgaver med rest >= minLiters tæller. Siloer uden markør → status noMarker; varer intet gårdlager tager → status noFarmStore.
  2. Rækkefølge: fuldeste rest først; lige → lavest silo-id (stabilt).
  3. Vogne: ledige pladser = maxVehicles - #aktive lån. For hver opgave i rækkefølge, så længe der er pladser: nærmeste ledige vogn (til siloen), der kan bære varen; resten reduceres med vognens kapacitet; samme opgave får flere vogne, så længe resten stadig er >= minLiters.
  4. Gårdlager pr. lån: nærmeste gårdlager (til siloen) der tager varen med freeLiters >= min(vognens kapacitet, rest); ellers det med mest plads; ellers intet (opgaven springes over denne runde).

Output: {dispatch = {{vehicleId, siloId, siloMarkerId, fillType, storeMarkerId, liters}}, status = {...}}.

Udførelse (adFieldSilos.lua)

  • Takt: planlæg hvert 60. s (spiltid via dt), kun når flowet kører. Lagertal læses som i dag (ADSmartPickup.getStationLevelAndCapacity / silo-lagre).
  • Ledige vogne: ADFieldWork.getRigs(adEnv) filtreret til enabled and not busy and not controlled, og vogne der har aflæsbare enheder (AutoDrive.getAllDischargeableUnits), der understøtter varen. getRigs.busy udvides med ADFieldSilos.isLoaned(vehicle), så markarbejdet ikke tager en lånt vogn (flows tager allerede kun deres egne tilknyttede vogne).
  • Afsend: AutoDrive "Hent og aflever": første markør = silomarkør, anden = gårdlagerets markør, vare = lånets vare, loopCounter = 1, parkering ved job slut slået til (enableParkAtJobFinished); start som markarbejdet (startAd → mode:start). Log: marksilo: '<vogn>' henter <liter> l <vare> i <silo> → <lager>.
  • Frigivelse: lånet slettes når AD ikke længere er aktivt for vognen (turen og parkeringen er færdig), når spilleren sætter sig i den, eller når flowet stoppes (stop = AD stoppes på lånte vogne).
  • Vagt: er vognen ikke kommet i gang (ingen stigning i fyldning og står stille) efter 120 s, stoppes AD, lånet slettes, og der logges én advarsel pr. (silo, vare), så samme opgave ikke fejler i ring hvert minut (opgaven får 10 min pause).
  • Genindlæsning: lån gemmes ikke. Ved indlæsning er alle vogne frie for flowet; en vogn AutoDrive selv genstarter, kører sin tur færdig som almindelig AD-tur.

GUI

Flow-fanen: typen "Marksiloer" kan oprettes (højst én). Indstillinger: gårdlagre (eksisterende vælger), "Maks. vogne ude" (1–10), "Mindste mængde" (5.000 / 10.000 / 25.000 / 50.000 l), Start/Stop. Status: x/y vogne ude · n siloer venter, og én række pr. marksilo med indhold: silo, vare, liter, på vej, status (ok / mangler markør / ingen gård tager <vare>). Tekster i l10n_da + l10n_en (spu_fs_*).

Uden for scope

  • Salg direkte fra marksilo (kan senere bruge udkørslens prisregel).
  • Faste vogne i flowet (valg 1 i brainstorm) — fravalgt.
  • Lån der overlever genindlæsning.

Test

  • tests/test_adFieldSiloPlanner.lua: kvalificering (tærskel, markør, gård tager varen), fuldeste først, x-loft inkl. aktive lån, flere vogne til én stor silo, vogn der ikke kan bære varen springes over, nærmeste gårdlager med plads, fallback til mest plads, intet lager → ingen afsendelse.
  • tests/test_adRuns.lua: ny kind gemmes/indlæses med maxVehicles/minLiters; ukendt kind → supply som før.
  • In-game: silo ved en mark med 50.000 l hvede, gårdlager = Farma-silo, x = 2 → to vogne kører, afleverer, parkerer; markarbejdet tager ikke de lånte vogne imens.