Files
fs25-adsmartpickup/docs/superpowers/specs/2026-09-28-maskinpulje-design.md
T

9.2 KiB
Raw Blame History

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.rearImplements tom), ikke i et flow (ADRunsController.getRunForVehicle == nil), ikke optaget (samme busy-regel som getRigs), 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 via ADFieldFleet.ROLE_SPECS; vogn med spec_trailer + spec_dischargeable og 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), ellers tractorPower >= 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 med powerOk. Returnerer pair eller nil, why, args (noPoolImplement / noPoolTractor / tooWeak med hk-tal).
  • ADPool.queueOrder(fields) — markers ventende rækkefølge: waitingSince stigende, 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, tractors fra g_currentMission.vehicleSystem.vehicles (gårdens), med position, rolle, specs til acceptFor, hk og parkering/Connect-id.
  • hk: g_storeManager:getItemByXMLFilename(vehicle.configFileName).specs → traktor power, redskab neededPower; 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. Returnerer pick/pickMany intet (noRig/allBusy/ cannotDo), forsøges ADPool.pairFor for de manglende. Puljekombinationens assignment får phase = "fetching", pool = {implementId, connectId, implementParkId, tractorParkId}, nøgle = traktorens id.
  • follow: fase fetching → når ADHitch.fetch melder ok: bredde tjekkes med redskabet på (checkWidth; for bred → hjemtur + årsag tooWide), derefter samme vej som i dag (startAd til markens markør / påfyldning, phase = "driving"). Fejl → hjemtur, karantæne, markens retryAt som ved noRig.
  • finishAssignment: har traktoren et puljeredskab bag sig (ADPool.isReturnDue) → ADHitch.returnHome i stedet for den almindelige parkeringstur; fase returning; assignment slettes, når hjemturen er færdig (eller fejler — så med advarsel).
  • Kø: tick gennemgår ventende marker i ADPool.queueOrder. waitingSince sæ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: startUnloader som i dag. Assignmentet bliver hos marken, til høststadiet er slut (som i dag); først da returnHome. Ingen frigivelse mellem læs.

Marksilo-flowet (adFieldSilos.lua, adFieldSiloPlanner.lua)

  • collectVehicles tilføjer puljekombinationer (puljevogn der kan bære varen + nærmeste puljetraktor) som kandidater med pool = {...}; planneren behandler dem som vogne (position = vognens).
  • withoutHarvestReserve tæ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

  1. 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.
  2. v1.49.0.0 — tømmevogn ved høst fra puljen.
  3. 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), roleOf inkl. 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.