fix(pulje): review v1.50 — egne tømmevogne virkede ikke under høst (global 'implement'), hentning kan afbrydes (høst slut/Stop/spiller), hjemtur ved tømmevogns-fejl, marksilo-lån kan ikke hænge i 'henter' (tidsgrænse, spiller, fejl i start), ingen ekstra parkeringstur med puljevogn, Stop holder en bar mark; regressionstest for fejlagtige globale (v1.50.1.0)

This commit is contained in:
2026-09-28 19:02:28 +02:00
parent 6f46bb543a
commit 5a2701fc62
11 changed files with 123 additions and 14 deletions
+5 -1
View File
@@ -40,7 +40,11 @@ end
ADFieldFleet.EXTRA_ROLES = {plow = {plow = true, cultivator = true}} ADFieldFleet.EXTRA_ROLES = {plow = {plow = true, cultivator = true}}
function ADFieldFleet.rolesFor(role) function ADFieldFleet.rolesFor(role)
return ADFieldFleet.EXTRA_ROLES[role] local roles = ADFieldFleet.EXTRA_ROLES[role]
if roles == nil then return nil end
local copy = {}
for key, value in pairs(roles) do copy[key] = value end
return copy
end end
-- Kandidater med rollen, sorteret nærmest først, delt i brugbare og afviste (med første grund). -- Kandidater med rollen, sorteret nærmest først, delt i brugbare og afviste (med første grund).
+5
View File
@@ -159,6 +159,7 @@ end
function ADFieldModel.setTarget(field, fruitName) function ADFieldModel.setTarget(field, fruitName)
local copy = copyField(field) local copy = copyField(field)
copy.plan.targetFruit = fruitName or "" copy.plan.targetFruit = fruitName or ""
copy.held = nil
copy.plan.mode = copy.plan.targetFruit ~= "" and "auto" or "manual" copy.plan.mode = copy.plan.targetFruit ~= "" and "auto" or "manual"
if not ADFieldModel.isWorking(field) and field.stage == "done" then if not ADFieldModel.isWorking(field) and field.stage == "done" then
copy.stage = "idle" copy.stage = "idle"
@@ -172,6 +173,7 @@ end
function ADFieldModel.shouldStartBare(field, kind) function ADFieldModel.shouldStartBare(field, kind)
if field.plan.targetFruit == nil or field.plan.targetFruit == "" then return false end if field.plan.targetFruit == nil or field.plan.targetFruit == "" then return false end
-- kun fra idle: efter egen såning står marken "done" (nysået kan læses som bar) — ingen dobbelt-såning -- kun fra idle: efter egen såning står marken "done" (nysået kan læses som bar) — ingen dobbelt-såning
if field.held and not field.startRequested then return false end
return kind == "bare" and field.stage == "idle" return kind == "bare" and field.stage == "idle"
end end
@@ -277,6 +279,7 @@ end
-- currentFruit (valgfri): afgrøden på marken nu; med mål-afgrøde udfyldes planen ud fra den. -- currentFruit (valgfri): afgrøden på marken nu; med mål-afgrøde udfyldes planen ud fra den.
function ADFieldModel.start(field, kind, needs, currentFruit) function ADFieldModel.start(field, kind, needs, currentFruit)
local copy = copyField(field) local copy = copyField(field)
copy.held = nil
copy.plan = ADFieldModel.applyTarget(copy.plan, kind, currentFruit) copy.plan = ADFieldModel.applyTarget(copy.plan, kind, currentFruit)
local stages = ADFieldModel.workStages(copy.plan, kind, needs) local stages = ADFieldModel.workStages(copy.plan, kind, needs)
copy.stage = stages[1] or "done" copy.stage = stages[1] or "done"
@@ -320,6 +323,8 @@ function ADFieldModel.stop(field)
end end
copy.startRequested = false copy.startRequested = false
copy.reason = nil copy.reason = nil
-- stoppet af spilleren: en bar mark med mål-afgrøde starter ikke selv igen (Start eller nyt mål slipper)
copy.held = true
return copy return copy
end end
+32 -6
View File
@@ -17,6 +17,7 @@ ADFieldSilos.CARGO_MIN_LITERS = 100 -- rest under dette tæller ikke som last
ADFieldSilos.FARM_RADIUS = 100 ADFieldSilos.FARM_RADIUS = 100
-- Siloer højst så langt fra en nabo hører til samme klynge (Farma-rækker: 15 m mellem siloer, 18 m mellem rækker) -- Siloer højst så langt fra en nabo hører til samme klynge (Farma-rækker: 15 m mellem siloer, 18 m mellem rækker)
ADFieldSilos.CLUSTER_LINK = 60 ADFieldSilos.CLUSTER_LINK = 60
ADFieldSilos.FETCH_TIMEOUT_MS = 300000 -- så længe må en traktor være om at hente en puljevogn
ADFieldSilos.MOVING_SPEED = 0.00028 -- m/ms, samme grænse som AutoDrive ADFieldSilos.MOVING_SPEED = 0.00028 -- m/ms, samme grænse som AutoDrive
ADFieldSilos.FILE_NAME = "ADSmartPickup_fieldsilos.xml" ADFieldSilos.FILE_NAME = "ADSmartPickup_fieldsilos.xml"
ADFieldSilos.ROOT = "ADSmartPickupFieldSilos" ADFieldSilos.ROOT = "ADSmartPickupFieldSilos"
@@ -340,7 +341,7 @@ local function fillTypeName(fillType)
return desc ~= nil and (desc.title or desc.name) or tostring(fillType) return desc ~= nil and (desc.title or desc.name) or tostring(fillType)
end end
local function dispatchOne(adEnv, order, vehicle, silosById, storesById) local function dispatchOne(adEnv, order, vehicle, silosById, storesById, isPool)
local module = vehicle.ad.stateModule local module = vehicle.ad.stateModule
module:setMode(adEnv.AutoDrive.MODE_PICKUPANDDELIVER) module:setMode(adEnv.AutoDrive.MODE_PICKUPANDDELIVER)
module:setFirstMarkerByWayPointId(order.siloMarkerId) module:setFirstMarkerByWayPointId(order.siloMarkerId)
@@ -349,7 +350,9 @@ local function dispatchOne(adEnv, order, vehicle, silosById, storesById)
module:setFillType(order.fillType) module:setFillType(order.fillType)
module.loopCounter = 1 module.loopCounter = 1
if module.setLoopsDone ~= nil then module:setLoopsDone(0) end if module.setLoopsDone ~= nil then module:setLoopsDone(0) end
ADFieldWork.enableParkAtJobFinished(vehicle) -- puljevogn: ingen AD-parkering — ved turens slut sætter returnHome vognen af og kører traktoren hjem
-- (med AD-parkering kørte den først hjem med vognen og så tilbage efter den)
if not isPool then ADFieldWork.enableParkAtJobFinished(vehicle) end
-- rotation fra: ellers kan modens egne pickup-hooks sende vognen til en anden silo i mappen -- rotation fra: ellers kan modens egne pickup-hooks sende vognen til en anden silo i mappen
if ADRunsController ~= nil and ADRunsController.setSetting ~= nil then if ADRunsController ~= nil and ADRunsController.setSetting ~= nil then
ADRunsController.setSetting(adEnv, vehicle, "rotateTargets", adEnv.AutoDrive.RT_NONE) ADRunsController.setSetting(adEnv, vehicle, "rotateTargets", adEnv.AutoDrive.RT_NONE)
@@ -371,7 +374,6 @@ local function dispatchPool(adEnv, order, pair, silosById, storesById)
local owner = {siloId = order.siloId, storeId = order.storeId, siloName = silo ~= nil and silo.name or order.siloId, local owner = {siloId = order.siloId, storeId = order.storeId, siloName = silo ~= nil and silo.name or order.siloId,
fillType = order.fillType, liters = order.liters, startedMs = nowMs, lastProgressMs = nowMs, lastFill = 0, fetching = true} fillType = order.fillType, liters = order.liters, startedMs = nowMs, lastProgressMs = nowMs, lastFill = 0, fetching = true}
loans[tractor] = owner loans[tractor] = owner
ADPool.reserve(owner, {pair.implement.id, pair.tractor.id})
ADHitch.fetch(adEnv, tractor, pair.implement.connectId, function(_, ok, detail) ADHitch.fetch(adEnv, tractor, pair.implement.connectId, function(_, ok, detail)
ADPool.release(owner) ADPool.release(owner)
if loans[tractor] ~= owner then return end -- lånet blev afbrudt imens (Stop alt / flow slået fra) if loans[tractor] ~= owner then return end -- lånet blev afbrudt imens (Stop alt / flow slået fra)
@@ -385,8 +387,14 @@ local function dispatchPool(adEnv, order, pair, silosById, storesById)
if park ~= nil then ADFieldWork.startAd(adEnv, tractor, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end if park ~= nil then ADFieldWork.startAd(adEnv, tractor, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
return return
end end
dispatchOne(adEnv, order, tractor, silosById, storesById) local okDispatch, err = pcall(dispatchOne, adEnv, order, tractor, silosById, storesById, true)
if not okDispatch then
Logging.warning(ADFieldSilos.LOG_PREFIX .. "'%s' kunne ikke starte turen med puljevognen: %s", tostring(ADRuns.vehicleLabel(tractor)), tostring(err))
ADFieldSilos.releaseVehicle(adEnv, tractor, "failed")
end
end) end)
-- reservationen først når hentningen er sat i gang (fejler fetch, er der intet at frigive)
ADPool.reserve(owner, {pair.implement.id, pair.tractor.id})
Logging.info(ADFieldSilos.LOG_PREFIX .. "'%s' henter puljevognen '%s' til %d l %s i %s", tostring(ADRuns.vehicleLabel(tractor)), Logging.info(ADFieldSilos.LOG_PREFIX .. "'%s' henter puljevognen '%s' til %d l %s i %s", tostring(ADRuns.vehicleLabel(tractor)),
tostring(pair.implement.name), math.floor(order.liters), fillTypeName(order.fillType), tostring(silo ~= nil and silo.name or order.siloId)) tostring(pair.implement.name), math.floor(order.liters), fillTypeName(order.fillType), tostring(silo ~= nil and silo.name or order.siloId))
end end
@@ -395,6 +403,11 @@ local function release(adEnv, vehicle, reason)
local loan = loans[vehicle] local loan = loans[vehicle]
loans[vehicle] = nil loans[vehicle] = nil
if loan == nil then return end if loan == nil then return end
if loan.fetching then
-- henter stadig puljevognen: afbryd koblingen og frigiv reservationen
if ADHitch ~= nil then ADHitch.cancel(vehicle) end
if ADPool ~= nil then ADPool.release(loan) end
end
if reason == "stuck" or reason == "failed" then if reason == "stuck" or reason == "failed" then
local k = ADFieldSiloPlanner.key(loan.siloId, loan.fillType) local k = ADFieldSiloPlanner.key(loan.siloId, loan.fillType)
paused[k] = nowMs + ADFieldSilos.PAUSE_MS paused[k] = nowMs + ADFieldSilos.PAUSE_MS
@@ -416,6 +429,10 @@ local function release(adEnv, vehicle, reason)
end end
end end
function ADFieldSilos.releaseVehicle(adEnv, vehicle, reason)
release(adEnv, vehicle, reason)
end
function ADFieldSilos.stopAll(adEnv) function ADFieldSilos.stopAll(adEnv)
local list = {} local list = {}
for vehicle in pairs(loans) do table.insert(list, vehicle) end for vehicle in pairs(loans) do table.insert(list, vehicle) end
@@ -431,8 +448,17 @@ local function checkLoans(adEnv)
else else
local ok, err = pcall(function() local ok, err = pcall(function()
local loan = loans[vehicle] local loan = loans[vehicle]
-- henter puljevognen: AD holder stille under koblingen — ikke "færdig" -- henter puljevognen: AD holder stille under koblingen — ikke "færdig"; men spilleren kan overtage,
if loan.fetching then return end -- og en hentning der ikke bliver færdig (trafik, rute), opgives
if loan.fetching then
local controlled = vehicle.getIsControlled ~= nil and vehicle:getIsControlled() or false
if controlled then
release(adEnv, vehicle, "player")
elseif nowMs - (loan.startedMs or nowMs) > ADFieldSilos.FETCH_TIMEOUT_MS then
release(adEnv, vehicle, "stuck")
end
return
end
local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil
local fill = fillLevel(adEnv, vehicle) local fill = fillLevel(adEnv, vehicle)
local vehicleState = { local vehicleState = {
+23 -4
View File
@@ -287,6 +287,10 @@ end
function ADFieldWork.release(assignment, phase) function ADFieldWork.release(assignment, phase)
restoreToolOffset(assignment) restoreToolOffset(assignment)
if assignment.handle ~= nil then assignment.handle.cancelled = true end if assignment.handle ~= nil then assignment.handle.cancelled = true end
-- henter stadig puljeredskabet: afbryd koblingen, så det ikke kobles på uden en opgave
if assignment.phase == "fetching" and assignment.hitch ~= nil and not assignment.hitch.done and ADHitch ~= nil then
ADHitch.cancel(assignment.vehicle)
end
assignment.phase = phase or "released" assignment.phase = phase or "released"
if ADPool ~= nil and assignment.pool ~= nil then ADPool.release(assignment) end if ADPool ~= nil and assignment.pool ~= nil then ADPool.release(assignment) end
ADFieldJobs.state.assignments[assignment.vehicleId] = nil ADFieldJobs.state.assignments[assignment.vehicleId] = nil
@@ -447,8 +451,6 @@ function ADFieldWork.dispatch(adEnv, field, info, decision)
local offNetwork = {} local offNetwork = {}
local accept = function(candidate) local accept = function(candidate)
if roleAccept ~= nil and not roleAccept(candidate) then return false end if roleAccept ~= nil and not roleAccept(candidate) then return false end
-- tømmevogn: skal kunne bære høstens vare
if role == "unloader" and not ADPool.canCarry(implement, info.harvestFillType) then return false end
-- manuel transport: spilleren kører den — afstand til AutoDrive-vejnettet er ligegyldig -- manuel transport: spilleren kører den — afstand til AutoDrive-vejnettet er ligegyldig
if role == "harvester" and candidate.manual then return true end if role == "harvester" and candidate.manual then return true end
local d = candidate.x ~= nil and ADFieldWork.distanceToNetwork(adEnv, candidate.x, candidate.z) or nil local d = candidate.x ~= nil and ADFieldWork.distanceToNetwork(adEnv, candidate.x, candidate.z) or nil
@@ -697,6 +699,7 @@ local function beginUnloader(adEnv, field, info, assignment)
local store, why = ADFieldWork.chooseStore(adEnv, field, info, vehicle, fillType) local store, why = ADFieldWork.chooseStore(adEnv, field, info, vehicle, fillType)
if store == nil then if store == nil then
ADFieldWork.release(assignment) ADFieldWork.release(assignment)
ADHitch.returnHome(adEnv, vehicle)
fail(field.id, "intet lager til høsten: " .. tostring(why)) fail(field.id, "intet lager til høsten: " .. tostring(why))
return return
end end
@@ -716,11 +719,13 @@ local function beginUnloader(adEnv, field, info, assignment)
log(field.id, "aflæsningsvogn '%s' følger høsteren -> %s", ADRuns.vehicleLabel(vehicle), tostring(store.name)) log(field.id, "aflæsningsvogn '%s' følger høsteren -> %s", ADRuns.vehicleLabel(vehicle), tostring(store.name))
else else
ADFieldWork.release(assignment) ADFieldWork.release(assignment)
ADHitch.returnHome(adEnv, vehicle)
fail(field.id, "aflæsningsvogn: " .. tostring(reason)) fail(field.id, "aflæsningsvogn: " .. tostring(reason))
end end
end) end)
if handle == nil then if handle == nil then
ADFieldWork.release(assignment) ADFieldWork.release(assignment)
ADHitch.returnHome(adEnv, vehicle)
fail(field.id, "aflæsningsvogn: " .. tostring(err)) fail(field.id, "aflæsningsvogn: " .. tostring(err))
return return
end end
@@ -1284,7 +1289,16 @@ end
-- Høsten er færdig: aflæsningsvognene stoppes; har de rest, kører den til lager, ellers parkering. -- Høsten er færdig: aflæsningsvognene stoppes; har de rest, kører den til lager, ellers parkering.
function ADFieldWork.windDownHelpers(adEnv, fieldId, stage) function ADFieldWork.windDownHelpers(adEnv, fieldId, stage)
for _, assignment in ipairs(ADFieldJobs.assignmentsFor(fieldId)) do for _, assignment in ipairs(ADFieldJobs.assignmentsFor(fieldId)) do
if assignment.helper and assignment.stage == stage then if assignment.helper and assignment.stage == stage and assignment.phase == "fetching" then
-- høsten sluttede mens puljevognen blev hentet: afbryd, vognen tilbage hvis den nåede at komme på
local vehicle = assignment.vehicle
ADFieldWork.release(assignment)
if not ADHitch.returnHome(adEnv, vehicle) then
local park = parkMarkerId(adEnv, vehicle)
if park ~= nil then startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
end
log(fieldId, "tømmevogn '%s' afbrudt under hentning — høsten er færdig", ADRuns.vehicleLabel(vehicle))
elseif assignment.helper and assignment.stage == stage then
if assignment.handle ~= nil then assignment.handle.cancelled = true end if assignment.handle ~= nil then assignment.handle.cancelled = true end
ADCpBridge.stop(assignment.vehicle) ADCpBridge.stop(assignment.vehicle)
assignment.phase = "working" assignment.phase = "working"
@@ -1315,7 +1329,12 @@ function ADFieldWork.stopAll(adEnv, fieldId)
for _, assignment in ipairs(ADFieldJobs.assignmentsFor(fieldId)) do for _, assignment in ipairs(ADFieldJobs.assignmentsFor(fieldId)) do
pcall(stopAd, assignment.vehicle) pcall(stopAd, assignment.vehicle)
ADCpBridge.stop(assignment.vehicle) ADCpBridge.stop(assignment.vehicle)
local wasFetching = assignment.phase == "fetching"
ADFieldWork.release(assignment) ADFieldWork.release(assignment)
pcall(ADHitch.returnHome, adEnv, assignment.vehicle) local okHome, pooled = pcall(ADHitch.returnHome, adEnv, assignment.vehicle)
if wasFetching and not (okHome and pooled) then
local park = parkMarkerId(adEnv, assignment.vehicle)
if park ~= nil then pcall(startAd, adEnv, assignment.vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
end
end end
end end
+10
View File
@@ -253,6 +253,16 @@ local function start(adEnv, vehicle, markerId, action, onDone)
return job return job
end end
-- Afbryd et hente-/koble-job (Stop alt, høsten slut, spilleren overtager): intet kobles på bagefter, og
-- onDone kaldes ikke. -> true hvis der var et job.
function ADHitch.cancel(vehicle)
local had = jobs[vehicle] ~= nil
jobs[vehicle] = nil
if ADPool ~= nil and ADPool.setReturning ~= nil then ADPool.setReturning(vehicle, false) end
if had and vehicle.stopAutoDrive ~= nil then pcall(vehicle.stopAutoDrive, vehicle) end
return had
end
-- Kør til en Connect-markør og kobl på. onDone(vehicle, ok, redskab eller årsag) kaldes én gang. -- Kør til en Connect-markør og kobl på. onDone(vehicle, ok, redskab eller årsag) kaldes én gang.
function ADHitch.fetch(adEnv, vehicle, markerId, onDone) function ADHitch.fetch(adEnv, vehicle, markerId, onDone)
return start(adEnv, vehicle, markerId, "attach", onDone) return start(adEnv, vehicle, markerId, "attach", onDone)
+13 -2
View File
@@ -277,8 +277,18 @@ function ADPool.readNeededHp(vehicle)
return item.specs ~= nil and ADPool.numberOf(item.specs.neededPower) or nil return item.specs ~= nil and ADPool.numberOf(item.specs.neededPower) or nil
end end
-- Traktorens effekt i hk: motorens topeffekt (kW) omregnet; ellers butiksdata. local tractorHpCache = setmetatable({}, {__mode = "k"}) -- vehicle -> hk eller false
-- Traktorens effekt i hk: motorens topeffekt (kW) omregnet; ellers butiksdata. Gemmes pr. traktor.
local function tractorHpOf(vehicle) local function tractorHpOf(vehicle)
local cached = tractorHpCache[vehicle]
if cached ~= nil then return cached or nil end
local value = ADPool.readTractorHp(vehicle)
tractorHpCache[vehicle] = value or false
return value
end
function ADPool.readTractorHp(vehicle)
local motor = vehicle.spec_motorized ~= nil and vehicle.spec_motorized.motor or nil local motor = vehicle.spec_motorized ~= nil and vehicle.spec_motorized.motor or nil
local kw = motor ~= nil and motor.peakMotorPower or nil local kw = motor ~= nil and motor.peakMotorPower or nil
if type(kw) == "number" and kw > 0 then return kw * 1.35962 end if type(kw) == "number" and kw > 0 then return kw * 1.35962 end
@@ -385,8 +395,9 @@ function ADPool.overview(adEnv)
local state = ADFieldJobs.state local state = ADFieldJobs.state
for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do
local id = ADRunsController.getVehicleId(vehicle) local id = ADRunsController.getVehicleId(vehicle)
-- en traktor med et redskab der giver den en markrolle, står allerede i flåden som kombination
if id ~= nil and vehicle.spec_attacherJoints ~= nil and ADRunsController.getRunForVehicle(vehicle) == nil if id ~= nil and vehicle.spec_attacherJoints ~= nil and ADRunsController.getRunForVehicle(vehicle) == nil
and ADPool.canPull(ADPool.ownRole(vehicle)) then and ADPool.canPull(ADPool.ownRole(vehicle)) and ADFieldFleet.roleFromSpecs(ADCpBridge.getSpecs(vehicle)) == nil then
local x, z = positionOf(vehicle) local x, z = positionOf(vehicle)
local distance = ADFieldWork.distanceToNetwork(adEnv, x, z) local distance = ADFieldWork.distanceToNetwork(adEnv, x, z)
local assignment = state.assignments[id] local assignment = state.assignments[id]
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?> <?xml version="1.0" encoding="utf-8" standalone="no"?>
<modDesc descVersion="107"> <modDesc descVersion="107">
<author>masterdraco</author> <author>masterdraco</author>
<version>1.50.0.0</version> <version>1.50.1.0</version>
<title> <title>
<en>AD Smart Pickup</en> <en>AD Smart Pickup</en>
</title> </title>
+1
View File
@@ -140,5 +140,6 @@ check("FLP plov kan pløje", F.rolesFor("plow").plow, true)
check("FLP kultivator kan ikke pløje", F.rolesFor("cultivator"), nil) check("FLP kultivator kan ikke pløje", F.rolesFor("cultivator"), nil)
local plough = {id = "p", role = "plow", roles = F.rolesFor("plow"), enabled = true, x = 0, z = 0, width = 3} local plough = {id = "p", role = "plow", roles = F.rolesFor("plow"), enabled = true, x = 0, z = 0, width = 3}
check("FLP plov vælges til kultivering", (F.pick({plough}, "cultivator", 0, 0, nil)).id, "p") check("FLP plov vælges til kultivering", (F.pick({plough}, "cultivator", 0, 0, nil)).id, "p")
check("FLP rolesFor giver en kopi", F.rolesFor("plow") ~= F.rolesFor("plow"), true)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1) os.exit(failures == 0 and 0 or 1)
+6
View File
@@ -310,5 +310,11 @@ check("M24 klar = ikke passiv", M.isPassive(M.with(calm, {stage = "ready"})), fa
check("M24 i gang = ikke passiv", M.isPassive(started), false) check("M24 i gang = ikke passiv", M.isPassive(started), false)
check("M24 Start nu = ikke passiv", M.isPassive(M.with(calm, {startRequested = true})), false) check("M24 Start nu = ikke passiv", M.isPassive(M.with(calm, {startRequested = true})), false)
-- Stop holder en bar mark (ellers starter klargøringen straks forfra); Start eller ny mål-afgrøde slipper
local stoppedBare = M.stop(M.with(target, {stage = "cultivating"}))
check("M21 stoppet bar mark starter ikke selv", M.shouldStartBare(stoppedBare, "bare"), false)
check("M21 Start slipper", M.shouldStartBare(M.with(stoppedBare, {startRequested = true}), "bare"), true)
check("M21 ny mål-afgrøde slipper", M.shouldStartBare(M.setTarget(stoppedBare, "BARLEY"), "bare"), true)
check("M21 start nulstiller hold (næste sæson starter selv)", M.start(stoppedBare, "bare", {}, "WHEAT").held, nil)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1) os.exit(failures == 0 and 0 or 1)
+9
View File
@@ -89,5 +89,14 @@ check("hjem: to trin", #home, 2); check("hjem: redskab først", home[1], 4); che
check("hjem: uden redskab kun traktor", #H.homeRoute({}, 2), 1) check("hjem: uden redskab kun traktor", #H.homeRoute({}, 2), 1)
check("hjem: samme parkering to gange tæller én", #H.homeRoute({4, 4}, 2), 2) check("hjem: samme parkering to gange tæller én", #H.homeRoute({4, 4}, 2), 2)
check("hjem: uden traktorparkering", #H.homeRoute({4}, nil), 1) check("hjem: uden traktorparkering", #H.homeRoute({4}, nil), 1)
-- afbrydelse: et hente-job kan annulleres (Stop alt, høst slut, spilleren overtager)
ADFieldWork = ADFieldWork or {startAd = function() end}
Logging = Logging or {info = function() end, warning = function() end}
local stubEnv = {ADGraphManager = {getMapMarkerByWayPointId = function() return {name = "Connect X"} end}, AutoDrive = {MODE_DRIVETO = 1}}
local tractorStub = {getFullName = function() return "T" end, stopAutoDrive = function(v) v.stopped = true end}
H.fetch(stubEnv, tractorStub, 9, function() end)
check("annullér: job fandtes", H.cancel(tractorStub), true)
check("annullér: AD stoppet", tractorStub.stopped, true)
check("annullér: intet job tilbage", H.cancel(tractorStub), false)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1) os.exit(failures == 0 and 0 or 1)
+18
View File
@@ -0,0 +1,18 @@
-- Kør: luajit tests/test_noStrayGlobals.lua (fra repo-roden)
-- Fanger lokale navne der ved en fejl bruges som globale (fx 'implement' uden for sin closure — v1.49 gjorde
-- egne tømmevogne ubrugelige under høst). Læser luajit-bytecode: GGET/GSET af typiske lokale navne.
local SUSPECT = {implement = true, candidate = true, vehicle = true, rig = true, pair = true, assignment = true,
tractor = true, loan = true, field = true, info = true, marker = true, job = true, owner = true, order = true}
local failures = 0
local files = io.popen("ls FS25_ADSmartPickup/*.lua FS25_ADSmartPickup/gui/*.lua"):read("*a")
for file in files:gmatch("[^\n]+") do
local listing = io.popen("luajit -bl " .. file .. " 2>&1"):read("*a")
for op, name in listing:gmatch("(G[GS]ET)%s+%d+%s+%d+%s+; \"([%w_]+)\"") do
if SUSPECT[name] then
failures = failures + 1
print(string.format("FAIL %s: %s af global '%s'", file, op, name))
end
end
end
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)