feat(markarbejde): efter genindlæsning genstartes CP-maskiner der var midt i et job fra sidste waypoint (CP's eget fortsæt-job; HUD'ens startpunkt urørt) og meldes ind på marken igen, hvis trinnet passer til rollen (v1.37.0.0)

This commit is contained in:
2026-09-27 13:51:44 +02:00
parent 2b3793eeaa
commit 565d7923cd
4 changed files with 91 additions and 1 deletions
+28
View File
@@ -44,6 +44,28 @@ local function cropGone(stage, info)
return (info.readyRatio or 0) < ADFieldModel.CUT_RATIO
end
-- Ligger (x, z) inden for omridset? (lige-ulige-reglen; kanten tæller som inde)
local function insidePolygon(x, z, verts)
local inside, j = false, #verts
for i = 1, #verts do
local a, b = verts[i], verts[j]
if (a.z > z) ~= (b.z > z) and x <= (b.x - a.x) * (z - a.z) / (b.z - a.z) + a.x then inside = not inside end
j = i
end
return inside
end
-- Efter genindlæsning: marken en CP-maskine står på, hvis markens aktuelle trin er maskinens rolle (ellers nil).
-- fields = {{id, stage, verts = {{x, z}}}}
function ADFieldJobs.resumeField(x, z, role, fields)
for _, field in ipairs(fields or {}) do
if #(field.verts or {}) >= 3 and ADFieldModel.roleFor(field.stage) == role and insidePolygon(x, z, field.verts) then
return field.id
end
end
return nil
end
-- Beslutning for én mark. assignments = sæt på marken ({phase, stage, helper}); kun sæt på det aktuelle
-- trin tæller (en aflæsningsvogn på vej hjem fra høsten forstyrrer ikke kultiveringen).
-- env = {raining = bool}: vejrfølsomme trin (høst/slå/vend/riv/hø) sendes ikke ud i regn.
@@ -340,6 +362,12 @@ function ADFieldJobs.tick(adEnv, dt)
-- lidt efter start, og indtil da ligner de maskiner ledige (in-game 26/9: kultivatoren blev taget midt
-- i spillerens eget CP-job 45 s efter indlæsning)
if ADFieldJobs.now < ADFieldJobs.STARTUP_GRACE_MS then return end
if not ADFieldJobs.resumedAfterLoad then
-- én gang, før noget nyt sendes ud: CP-maskiner der var midt i et job, fortsætter (og tæller som aktive)
ADFieldJobs.resumedAfterLoad = true
local okResume, errResume = pcall(ADFieldWork.resumeAfterLoad, adEnv)
if not okResume then Logging.warning(ADFieldJobs.LOG_PREFIX .. "genstart efter indlæsning fejlede: %s", tostring(errResume)) end
end
local env = ADFieldJobs.environment()
local slice = ADFieldJobs.tickCount % ADFieldJobs.PASSIVE_SLICES
local stepped = 0
+45
View File
@@ -811,6 +811,15 @@ local function followWorking(adEnv, field, assignment)
end
if ADCpBridge.isWorking(vehicle) or isAdActive(vehicle) then
assignment.idleSince = nil
assignment.seenWorking = true
return
end
-- genoptaget efter indlæsning: CP starter asynkront — vent til den kører, før "står stille" betyder færdig
if assignment.resumed and not assignment.seenWorking then
if now() - assignment.since > ADFieldWork.START_TIMEOUT_MS then
ADFieldWork.release(assignment)
fail(assignment.fieldId, string.format("'%s': Courseplay fortsatte ikke efter genindlæsning", ADRuns.vehicleLabel(vehicle)))
end
return
end
assignment.idleSince = assignment.idleSince or now()
@@ -827,6 +836,42 @@ local function followWorking(adEnv, field, assignment)
finishAssignment(adEnv, assignment)
end
-- Efter genindlæsning: spillet stopper alle arbejdere ved gem, og Courseplay genstarter dem ikke (in-game 27/9).
-- En maskine med CP-kursus og et husket waypoint (CP nulstiller det når kurset er kørt færdigt) var midt i et job:
-- start den fra sidste waypoint med CP's eget "fortsæt"-job (HUD'ens eget startpunkt røres ikke). Står den på en
-- mark hvis aktuelle trin er maskinens rolle, meldes den ind på marken igen, så den følges og trinnet afsluttes.
function ADFieldWork.resumeAfterLoad(adEnv)
local fields, stageById = {}, {}
for _, info in ipairs(ADFields.list()) do
local field = ADFieldJobs.getField(info.id)
if field ~= nil and ADFieldModel.isWorking(field) then
table.insert(fields, {id = info.id, stage = field.stage, verts = info.verts})
stageById[info.id] = field.stage
end
end
for _, rig in ipairs(ADFieldWork.getRigs(adEnv)) do
local vehicle = rig.vehicle
local wasWorking = vehicle.startCpAtLastWp ~= nil and vehicle.hasCpCourse ~= nil and vehicle:hasCpCourse()
and vehicle.getCpLastRememberedWaypointIx ~= nil and vehicle:getCpLastRememberedWaypointIx() ~= nil
if wasWorking and not rig.busy and not rig.controlled then
local ok, started = pcall(vehicle.startCpAtLastWp, vehicle)
if not ok then
Logging.warning(ADFieldJobs.LOG_PREFIX .. "'%s' kunne ikke genstartes: %s", tostring(rig.label), tostring(started))
elseif started then
local fieldId = ADFieldJobs.resumeField(rig.x, rig.z, rig.role, fields)
if fieldId ~= nil then
ADFieldJobs.state.assignments[rig.id] = {vehicleId = rig.id, vehicle = vehicle, fieldId = fieldId, role = rig.role,
stage = stageById[fieldId], helper = false, phase = "working", since = now(), width = rig.width,
groupSize = 1, leader = true, resumed = true}
log(fieldId, "'%s' fortsætter efter genindlæsning (Courseplay fra sidste waypoint)", tostring(rig.label))
else
Logging.info(ADFieldJobs.LOG_PREFIX .. "'%s' genstartet fra sidste waypoint efter genindlæsning", tostring(rig.label))
end
end
end
end
end
function ADFieldWork.follow(adEnv, assignment)
local vehicle = assignment.vehicle
-- Kun når spilleren selv KØRER (bevæger sig uden Courseplay/AutoDrive) slippes sættet — at sidde i
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<modDesc descVersion="107">
<author>masterdraco</author>
<version>1.36.7.0</version>
<version>1.37.0.0</version>
<title>
<en>AD Smart Pickup</en>
</title>
+17
View File
@@ -111,5 +111,22 @@ check("J14 uhøstet -> spol tilbage", J.decide(cultivatingField, {id = 16, marke
check("J14 høstrest 30 % -> kultiver", J.decide(cultivatingField, {id = 16, markerId = 9, kind = "harvest", phase = "ready", readyRatio = 0.3}, {}, 0).action ~= "rewind", true)
check("J14 stub -> kultiver", J.decide(cultivatingField, {id = 16, markerId = 9, kind = "bare", phase = "cut", readyRatio = 0}, {}, 0).action ~= "rewind", true)
-- resumeField: efter genindlæsning stopper spillet alle arbejdere; en CP-maskine der står PÅ en mark hvis
-- aktuelle trin passer til maskinens rolle, meldes ind på den mark igen (in-game 27/9)
do
local square = {{x = 0, z = 0}, {x = 100, z = 0}, {x = 100, z = 100}, {x = 0, z = 100}}
local fields = {
{id = 90, stage = "collecting", verts = square},
{id = 111, stage = "harvesting", verts = {{x = 200, z = 0}, {x = 300, z = 0}, {x = 300, z = 100}, {x = 200, z = 100}}},
}
check("RF høster på F111", ADFieldJobs.resumeField(250, 50, "harvester", fields), 111)
check("RF læssevogn på F90", ADFieldJobs.resumeField(50, 50, "collector", fields), 90)
check("RF forkert rolle til trinnet -> nil", ADFieldJobs.resumeField(250, 50, "collector", fields), nil)
check("RF uden for alle marker -> nil", ADFieldJobs.resumeField(150, 50, "harvester", fields), nil)
check("RF mark uden omrids -> nil", ADFieldJobs.resumeField(50, 50, "collector", {{id = 1, stage = "collecting", verts = {}}}), nil)
check("RF på kanten tæller som indenfor", ADFieldJobs.resumeField(0.5, 50, "collector", fields), 90)
end
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)