9.2 KiB
Maskinpulje — design
Dato: 2026-09-28 · Status: godkendt i chat (afsnit 1–4), afventer review af denne spec
Formål
Plove, harver, kultivatorer, såmaskiner, tømmevogne m.m. bruges kun en gang imellem. I dag skal hvert af dem have en traktor koblet fast på hele året, fordi markarbejdet kun kan sende en traktor, der allerede har det rigtige redskab bag sig. Maskinpuljen gør traktorer og redskaber til fælles puljer: et job venter i kø, til en traktor er ledig; traktoren henter det redskab, jobbet kræver, udfører arbejdet, parkerer redskabet på dets plads og kører selv hjem til sin egen parkering.
Succes: med fx 3 ledige traktorer, 2 plove og 1 kultivator bliver markernes arbejde udført uden at nogen traktor står låst til et redskab — færre køretøjer at købe og vedligeholde. Flows, der kører hele tiden (fodring, slurry, mælk …), påvirkes ikke.
Brugerens valg (fra brainstorm)
| Spørgsmål | Valg |
|---|---|
| Hvordan findes redskabets Connect-markør? | Navneregel: AD-parkering "X" ↔ markør "Connect X" |
| Hvem er i puljen? | Automatisk ud fra opsætningen — ingen afkrydsning |
| Hvilken traktor henter? | Nærmeste ledige med nok hk |
| Omfang | Markarbejde + tømmevogne ved høst + marksilo-flowet. Flows er undtaget |
| Tømmevogne ved høst | Også fra puljen, men dedikeret til marken, til høsten dér er færdig |
| Arkitektur | Udvid markarbejdets eget maskinvalg (ikke en separat puljemanager) |
Begreber
- Puljeredskab: et redskab eller en vogn, der holder frakoblet, har en AD-parkering (
advd.parkDestination→ markør "X"), og hvor der findes en markør "Connect X" (ADHitch.parseMarker= attach, navn = X; store/små bogstaver ligegyldigt). Uden Connect-markør er redskabet ikke i puljen — det er spillerens måde at holde det udenfor. - Puljevogn: puljeredskab med rollen
unloader(vogn med tip/snegl,spec_trailer+spec_dischargeable). - Puljetraktor: motoriseret køretøj uden noget koblet bag på (
ADHitch.rearImplementstom), ikke i et flow (ADRunsController.getRunForVehicle == nil), ikke optaget (sammebusy-regel somgetRigs), ikke styret af spilleren, med egen AD-parkering (vehicle.advd.parkDestination >= 1) og flueben i markflåden (ADFieldFleet.isEnabled). - Færdig kombination: det markarbejdet bruger i dag — traktor med redskabet allerede koblet på (
getRigs). - Puljekombination: {traktor, redskab, Connect-markør-id, redskabets parkering-id, traktorens parkering-id}.
AD-parkering: hver maskine har sin egen advd.parkDestination; AD bruger det valgte redskabs, når et er koblet på
(AutoDriveVehicleData.lua:88-95). Traktorens egen parkering læses derfor altid på traktoren selv.
Komponenter
adPool.lua (nyt, ren logik + tynd spil-adapter)
Ren logik (testes med luajit):
ADPool.roleOf(specs)— rolle for et frakoblet redskab ud fra dets egne specs viaADFieldFleet.ROLE_SPECS; vogn medspec_trailer+spec_dischargeableog intet andet →unloader.ADPool.isPoolImplement(item)—item = {attached, parkMarkerName, connectMarkerId}→ frakoblet, med parkering og Connect-markør.ADPool.powerOk(tractorPower, neededPower)— true når et af tallene mangler (nil/0), ellerstractorPower >= neededPower.ADPool.pairFor(role, fieldX, fieldZ, implements, tractors, reserved, accept)— redskab med rollen nærmest marken (ikke reserveret,accept(implement)sand), derefter nærmeste ledige traktor til redskabet medpowerOk. Returnererpairellernil, why, args(noPoolImplement/noPoolTractor/tooWeakmed hk-tal).ADPool.queueOrder(fields)— markers ventende rækkefølge:waitingSincestigende, lige → lavest mark-id.ADPool.isReturnDue(rearImplements, poolParkIds)— traktor har et puljeredskab bag sig (dets parkering har en Connect-markør) → hjemtur skal køres.
Spil-adapter:
ADPool.collect(adEnv)→implements, tractorsfrag_currentMission.vehicleSystem.vehicles(gårdens), med position, rolle, specs tilacceptFor, hk og parkering/Connect-id.- hk:
g_storeManager:getItemByXMLFilename(vehicle.configFileName).specs→ traktorpower, redskabneededPower; mangler de, bruges nil (→ tilladt). - Reservationer:
ADPool.reserve(implementId, tractorId, owner)/release(owner); i hukommelsen, ryddes ved genindlæsning (se Genindlæsning). - Karantæne: redskab, der ikke kunne kobles på, springes over i 10 min (
ADPool.QUARANTINE_MS = 600000).
adHitch.lua (findes, v1.47.4 — udvides let)
Udfører kørslerne: fetch (kør til Connect + kobl på), route (trin-tur, afkobling ved redskabets parkering).
Ny: ADHitch.returnHome(adEnv, tractor, onDone) = route({redskabets parkering, traktorens parkering}); ved
parkeringen kobles puljeredskabet af (samme regel som i dag i ruter).
Markarbejdet (adFieldWork.lua, adFieldJobs.lua)
dispatch: som i dag først færdige kombinationer. Returnererpick/pickManyintet (noRig/allBusy/cannotDo), forsøgesADPool.pairForfor de manglende. Puljekombinationens assignment fårphase = "fetching",pool = {implementId, connectId, implementParkId, tractorParkId}, nøgle = traktorens id.follow: fasefetching→ nårADHitch.fetchmelder ok: bredde tjekkes med redskabet på (checkWidth; for bred → hjemtur + årsagtooWide), derefter samme vej som i dag (startAdtil markens markør / påfyldning,phase = "driving"). Fejl → hjemtur, karantæne, markensretryAtsom vednoRig.finishAssignment: har traktoren et puljeredskab bag sig (ADPool.isReturnDue) →ADHitch.returnHomei stedet for den almindelige parkeringstur; fasereturning; assignment slettes, når hjemturen er færdig (eller fejler — så med advarsel).- Kø:
tickgennemgår ventende marker iADPool.queueOrder.waitingSincesættes, når en mark første gang ikke fik en maskine, og nulstilles ved udsendelse.DISPATCH_GAP_MS(10 s) beholdes. - Fanen viser faserne "henter X" og "sætter X af" og årsagerne
noPoolTractor/tooWeak.
Tømning ved høst
- Helper-dispatch (
role = "unloader",helper = true) bruger samme fallback: puljevogn + puljetraktor. - Efter
fetch:startUnloadersom i dag. Assignmentet bliver hos marken, til høststadiet er slut (som i dag); først dareturnHome. Ingen frigivelse mellem læs.
Marksilo-flowet (adFieldSilos.lua, adFieldSiloPlanner.lua)
collectVehiclestilføjer puljekombinationer (puljevogn der kan bære varen + nærmeste puljetraktor) som kandidater medpool = {...}; planneren behandler dem som vogne (position = vognens).withoutHarvestReservetæller puljevogne med, så høsten går først.- Lån med
pool:ADHitch.fetch→ AD "Hent og aflever" som i dag (enableParkAtJobFinished) → når AD er inaktiv:returnHome→ lånet slettes, når traktoren er hjemme. Vagten (120 s uden fremgang) starter efter koblingen.
Genindlæsning
Reservationer og assignments gemmes ikke (som i dag). Efter indlæsning ser en traktor med puljeredskab ud som en
færdig kombination; når markarbejdet eller marksilo-flowet afslutter et job med den, køres returnHome. Reglen
afhænger kun af, hvad der hænger bag traktoren, ikke af gemt tilstand. En traktor, som ingen af vores jobs bruger,
køres aldrig hjem af sig selv (spilleren kan have koblet et puljeredskab på for at køre selv).
Fejl
| Situation | Handling |
|---|---|
Kobling fejler (noAttachable, stoppedAway) |
Traktor hjem, redskab i karantæne 10 min, marken prøver igen (andet redskab eller venter) |
| Redskab for bredt når koblet på | Hjemtur, årsag tooWide i fanen |
| Spilleren sætter sig i traktoren | Assignment afbrydes som i dag; reservationer frigives |
| Ingen traktor stærk nok | Årsag tooWeak med hk-tal: "ingen traktor med ≥180 hk ledig til 'Plov 1'" |
| Hjemtur fejler | Advarsel i loggen; traktor og redskab frigives (spilleren må ordne det) |
Undtaget / uden for scope
- Flows (runs) — deres køretøjer er aldrig i puljen (uændret regel i
getRigs). - Vogne uden Connect-markør — dedikerede som i dag.
- Genbrug af et redskab direkte til næste mark uden at parkere (senere optimering).
- Flere redskaber pr. traktor (front + bag).
- Egen GUI-side for puljen.
Etaper
- v1.48.0.0 — markarbejde med pulje:
adPool.lua,returnHome, dispatch-fallback, fase fetching/returning, kø-rækkefølge, fane-tekster. In-game: savegame4, mark der skal harves/pløjes, redskab med parkering + Connect, solo-traktor henter → arbejder → parkerer → hjem. - v1.49.0.0 — tømmevogn ved høst fra puljen.
- v1.50.0.0 — marksilo med puljevogne (inkl. høst-reserve over puljevogne).
Test
tests/test_adPool.lua: puljeredskab ja/nej (koblet på, uden parkering, uden Connect),roleOfinkl.unloader,powerOk(nok/for lidt/manglende data),pairFor(redskab nærmest marken, traktor nærmest redskabet, reserveret og karantæne springes over,tooWeak/noPoolTractor/noPoolImplement),queueOrder,isReturnDue.tests/test_adHitch.lua:returnHome-rutens trin.tests/test_adFieldJobs.lua: færdig kombination foretrækkes; fallback til pulje; kø længst ventende først.tests/test_adFieldSiloPlanner.lua(etape 3): puljekandidater og høst-reserve med puljevogne.