feat(pulje): markarbejdet sender en solo-traktor efter et puljeredskab når ingen færdig kombination er ledig (fase fetching)
This commit is contained in:
@@ -129,6 +129,13 @@ end
|
||||
|
||||
-- ---- flåde ----
|
||||
|
||||
-- Optaget for markarbejdet: vores egen opgave, AutoDrive/Courseplay kører den, lånt af marksilo-flowet,
|
||||
-- eller på hjemtur fra puljen (sætter redskab af).
|
||||
local function isBusyVehicle(vehicle, id)
|
||||
return ADFieldJobs.state.assignments[id] ~= nil or isAdActive(vehicle) or ADCpBridge.isWorking(vehicle)
|
||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle)) or (ADPool ~= nil and ADPool.isReturning(vehicle))
|
||||
end
|
||||
|
||||
function ADFieldWork.getRigs(adEnv)
|
||||
local rigs = {}
|
||||
local state = ADFieldJobs.state
|
||||
@@ -144,12 +151,12 @@ function ADFieldWork.getRigs(adEnv)
|
||||
enabled = ADFieldFleet.isEnabled(state.fleetMode, state.fleet, id),
|
||||
-- optaget: vores egen opgave, eller AutoDrive/Courseplay kører den allerede (fx spillerens
|
||||
-- egen parkeringstur) — den må ikke kapres midt i en anden kørsel
|
||||
busy = state.assignments[id] ~= nil or isAdActive(vehicle) or ADCpBridge.isWorking(vehicle)
|
||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle)),
|
||||
busy = isBusyVehicle(vehicle, id),
|
||||
-- hvorfor optaget (til loggen, når ingen maskine kan sendes ud)
|
||||
busyWhy = (state.assignments[id] ~= nil and ("opgave F" .. tostring(state.assignments[id].fieldId)))
|
||||
or (isAdActive(vehicle) and "AutoDrive kører") or (ADCpBridge.isWorking(vehicle) and "Courseplay kører")
|
||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle) and "lånt af marksilo-flow") or nil,
|
||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle) and "lånt af marksilo-flow")
|
||||
or (ADPool ~= nil and ADPool.isReturning(vehicle) and "sætter redskab af") or nil,
|
||||
controlled = isControlledByPlayer(vehicle),
|
||||
-- manuel transport: spilleren kører den til marken (for bred til vejene med skærebord)
|
||||
manual = (state.manual or {})[id] == true,
|
||||
@@ -279,6 +286,7 @@ function ADFieldWork.release(assignment, phase)
|
||||
restoreToolOffset(assignment)
|
||||
if assignment.handle ~= nil then assignment.handle.cancelled = true end
|
||||
assignment.phase = phase or "released"
|
||||
if ADPool ~= nil and assignment.pool ~= nil then ADPool.release(assignment) end
|
||||
ADFieldJobs.state.assignments[assignment.vehicleId] = nil
|
||||
end
|
||||
|
||||
@@ -379,6 +387,44 @@ local function askPlayer(field, info, assignment, withDialog)
|
||||
end
|
||||
end
|
||||
|
||||
-- Puljekombination: nærmeste puljeredskab til marken + nærmeste ledige traktor med nok hk. Traktoren kører til
|
||||
-- "Connect X", kobler på og fortsætter så som en almindelig udsendelse (fase fetching -> driving).
|
||||
function ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept)
|
||||
local implements, tractors = ADPool.collect(adEnv, function(vehicle)
|
||||
return isBusyVehicle(vehicle, ADRunsController.getVehicleId(vehicle))
|
||||
end)
|
||||
local accept = function(implement)
|
||||
-- samme felter som getRigs giver sæt, så markens krav (frø, afgrøde, ukrudt) tjekkes på redskabet selv
|
||||
local candidate = {role = implement.role, roles = implement.roles, vehicle = implement.vehicle}
|
||||
if role == "seeder" then
|
||||
candidate.seedFruits = ADCpBridge.getSeedFruits(implement.vehicle)
|
||||
candidate.hasSeeds = ADCpBridge.hasSeeds(implement.vehicle)
|
||||
end
|
||||
if role == "weeder" then candidate.mechanical = ADCpBridge.isMechanicalWeeder(implement.vehicle) end
|
||||
if roleAccept ~= nil and not roleAccept(candidate) then return false end
|
||||
local required = ADFieldModel.requiredWidth(field, role)
|
||||
return (implement.width or 0) <= 0 or ADFieldModel.checkWidth(role, implement.width, required)
|
||||
end
|
||||
local pair, why, args = ADPool.pairFor(role, info.x, info.z, implements, tractors, ADPool.blocked(now()), accept)
|
||||
if pair == nil then return false, why, args end
|
||||
local tractor, implement = pair.tractor, pair.implement
|
||||
local assignment = {
|
||||
vehicleId = tractor.id, vehicle = tractor.vehicle, fieldId = field.id, role = role, stage = field.stage,
|
||||
helper = false, phase = "fetching", since = now(), width = implement.width, groupSize = 1, leader = true,
|
||||
startX = tractor.x, startZ = tractor.z,
|
||||
pool = {implementId = implement.id, implementName = implement.name, connectId = implement.connectId},
|
||||
hitch = {done = false},
|
||||
}
|
||||
ADFieldJobs.state.assignments[tractor.id] = assignment
|
||||
ADPool.reserve(assignment, {implement.id, tractor.id})
|
||||
ADHitch.fetch(adEnv, tractor.vehicle, implement.connectId, function(_, ok, detail)
|
||||
assignment.hitch = {done = true, ok = ok, detail = detail}
|
||||
end)
|
||||
note(field.id, {reason = {key = "spu_field_reason_fetching", name = implement.name}})
|
||||
log(field.id, "%s: '%s' henter '%s' (%s)", role, tractor.name, implement.name, "pulje")
|
||||
return true
|
||||
end
|
||||
|
||||
function ADFieldWork.dispatch(adEnv, field, info, decision)
|
||||
local role = decision.role
|
||||
local ok, reason = preflight(field, role)
|
||||
@@ -414,6 +460,20 @@ function ADFieldWork.dispatch(adEnv, field, info, decision)
|
||||
rigs = rig ~= nil and {rig} or nil
|
||||
end
|
||||
if rigs == nil then
|
||||
-- ingen færdig kombination: en ledig solo-traktor henter et puljeredskab (kun hovedopgaver, ikke tømmevogne)
|
||||
if not decision.helper and (decision.count or 1) == 1 and ADPool ~= nil
|
||||
and (why == "noRig" or why == "allBusy" or why == "cannotDo") then
|
||||
local pooled, poolWhy, poolArgs = ADFieldWork.dispatchPool(adEnv, field, info, role, roleAccept)
|
||||
if pooled then return end
|
||||
if poolWhy == "tooWeak" then
|
||||
note(field.id, {reason = {text = string.format("ingen ledig traktor med ≥%.0f hk til %s-redskabet",
|
||||
(poolArgs or {})[1] or 0, tostring(role))}, retryAt = now() + ADFieldWork.NO_RIG_RETRY_MS})
|
||||
return
|
||||
end
|
||||
if poolWhy == "noPoolTractor" and why ~= "allBusy" then
|
||||
why, args = poolWhy, poolArgs
|
||||
end
|
||||
end
|
||||
if #offNetwork > 0 and (why == "cannotDo" or why == "noRig") then
|
||||
-- de eneste med rollen står uden for AD-vejnettet
|
||||
note(field.id, {reason = {text = string.format("ingen %s kan køre til %s — står for langt fra AutoDrive-vejnettet (%s)",
|
||||
@@ -1093,7 +1153,38 @@ function ADFieldWork.follow(adEnv, assignment)
|
||||
local field = ADFieldJobs.getField(assignment.fieldId)
|
||||
local info = ADFields.getInfo(assignment.fieldId)
|
||||
wake(vehicle)
|
||||
if assignment.phase == "driving" then
|
||||
if assignment.phase == "fetching" then
|
||||
local hitch = assignment.hitch
|
||||
if not hitch.done then return end
|
||||
ADPool.release(assignment)
|
||||
if not hitch.ok then
|
||||
-- koblingen fejlede: redskabet i karantæne, traktoren hjem, marken prøver igen
|
||||
ADPool.quarantine(assignment.pool.implementId, now())
|
||||
ADFieldWork.release(assignment)
|
||||
note(assignment.fieldId, {retryAt = now() + ADFieldWork.NO_RIG_RETRY_MS,
|
||||
reason = {text = string.format("kunne ikke koble '%s' på (%s) — prøver et andet om lidt",
|
||||
tostring(assignment.pool.implementName), tostring(hitch.detail))}})
|
||||
local park = parkMarkerId(adEnv, vehicle)
|
||||
if park ~= nil then startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
|
||||
return
|
||||
end
|
||||
-- koblet på: bredden med redskabet på (for bred -> hjem igen)
|
||||
local width = ADCpBridge.getWorkWidth(vehicle)
|
||||
local okWidth, widthReason, widthArgs = ADFieldModel.checkWidth(assignment.role, width, ADFieldModel.requiredWidth(field, assignment.role))
|
||||
if not okWidth then
|
||||
ADFieldWork.release(assignment)
|
||||
note(assignment.fieldId, {retryAt = now() + ADFieldModel.RETRY_MS, reason = {key = "spu_field_reason_" .. tostring(widthReason), role = assignment.role, args = widthArgs}})
|
||||
ADHitch.returnHome(adEnv, vehicle)
|
||||
return
|
||||
end
|
||||
assignment.width, assignment.phase, assignment.since = width, "driving", now()
|
||||
assignment.startX, assignment.startZ = vehiclePosition(vehicle)
|
||||
startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, info.markerId, nil)
|
||||
assignment.drive = {mode = adEnv.AutoDrive.MODE_DRIVETO, first = info.markerId}
|
||||
note(assignment.fieldId, {reason = false})
|
||||
log(assignment.fieldId, "%s '%s' har '%s' på — kører til %s (%.1f m)", assignment.role, ADRuns.vehicleLabel(vehicle),
|
||||
tostring(assignment.pool.implementName), tostring(info.markerName), width or 0)
|
||||
elseif assignment.phase == "driving" then
|
||||
if not isAdActive(vehicle) and now() - assignment.since > 2000 then
|
||||
local x, z = vehiclePosition(vehicle)
|
||||
local wayPoint = info ~= nil and adEnv.ADGraphManager:getWayPointById(info.markerId) or nil
|
||||
|
||||
Reference in New Issue
Block a user