104 lines
6.7 KiB
Markdown
104 lines
6.7 KiB
Markdown
# 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. Det samme gælder siloer, der er kilde, mål eller lager i et flow (tilføjet efter review
|
||
2026-09-27: ellers tømte flowet gårdsiloer, som forsyningsflows bruger, fordi de ligger under 150 m fra en mark).
|
||
- **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
|
||
|
||
Marksilo-flowet er ÉN fast opsætning pr. savegame — ikke en ny run-type. Beslutning (2026-09-27, under
|
||
planlægning): run-editoren (`SmartPickupFrame`) er bygget til præcis to typer (forsyning/udkørsel) mange steder,
|
||
og runs har faste vogne, Start/Stop pr. vogn og Wait-puljer, som intet af det passer til lånte vogne. En egen
|
||
underfane + egen gemmefil giver langt færre indgreb i eksisterende kode.
|
||
|
||
Opsætning (`ADSmartPickup_fieldsilos.xml` i savegame-mappen, gemmes sammen med runs):
|
||
- `enabled` — til/fra, standard fra
|
||
- `storeIds` — gårdlagre (bygnings-id'er fra `ADBuildings`, kun `kind == "silo"`)
|
||
- `maxVehicles` — x, 1–10, standard 2
|
||
- `minLiters` — tærskel pr. silo og vare: 5000 / 10000 / 25000 / 50000, standard 10000
|
||
|
||
## 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:** kun vogne med AD-parkeringspunkt (ellers bliver de holdende på lagerets markør); `ADFieldWork.getRigs(adEnv)` filtreret til `role == "unloader"` (traktor + vogn, som Courseplay
|
||
godkender som tømmevogn — ikke sprøjter/høstere med tank), `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
|
||
|
||
Ny underfane "Marksiloer" efter "Måned". 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_adFieldSiloConfig.lua`: standarder, grænser (x 1–10, tærskel kun de fire værdier), til/fra af gårdlager, records frem og tilbage.
|
||
- 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.
|