From 3e9a8daa2d2a2091a80be64bdfeb342460f20bfc Mon Sep 17 00:00:00 2001 From: masterdraco Date: Fri, 25 Sep 2026 21:49:53 +0200 Subject: [PATCH] =?UTF-8?q?feat(marker):=20Courseplay-bro=20=E2=80=94=20st?= =?UTF-8?q?art=20markarbejde=20async,=20bredde=20og=20redskabs-specs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adCpBridge.lua | 98 +++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 FS25_ADSmartPickup/adCpBridge.lua diff --git a/FS25_ADSmartPickup/adCpBridge.lua b/FS25_ADSmartPickup/adCpBridge.lua new file mode 100644 index 0000000..ebeb5a7 --- /dev/null +++ b/FS25_ADSmartPickup/adCpBridge.lua @@ -0,0 +1,98 @@ +-- AD Courseplay Bridge +-- Den eneste kode der rører Courseplay: start markarbejde på en mark (grænse -> kursus -> start, alt +-- async), og læs om et sæt arbejder. Opskriften er bevist i spillet i AI-Bonden (AIHelperGlue.startCP): +-- CP kalder grænse-callbacken to gange (først false ved fejl) — kun første kald tæller. + +ADCpBridge = {} + +ADCpBridge.SPECS = {"spec_mower", "spec_tedder", "spec_windrower", "spec_forageWagon"} + +function ADCpBridge.isAvailable() + return AIJobType ~= nil and AIJobType.FIELDWORK_CP ~= nil +end + +local function collect(vehicle, list) + list = list or {} + table.insert(list, vehicle) + if vehicle.getAttachedImplements ~= nil then + for _, implement in ipairs(vehicle:getAttachedImplements()) do + if implement.object ~= nil then collect(implement.object, list) end + end + end + return list +end + +function ADCpBridge.getSpecs(vehicle) + local specs = {} + for _, object in ipairs(collect(vehicle)) do + for _, name in ipairs(ADCpBridge.SPECS) do + if object[name] ~= nil then specs[name] = true end + end + end + return specs +end + +function ADCpBridge.getWorkWidth(vehicle) + local best = 0 + for _, object in ipairs(collect(vehicle)) do + if object.getAIMarkers ~= nil then + pcall(function() if object.updateAIMarkerWidth ~= nil then object:updateAIMarkerWidth() end end) + local ok, _, _, _, _, width = pcall(object.getAIMarkers, object) + if ok and type(width) == "number" and width > best then best = width end + end + end + return best +end + +function ADCpBridge.isWorking(vehicle) + if vehicle.getIsCpFieldWorkActive ~= nil and vehicle:getIsCpFieldWorkActive() then return true end + return vehicle.getIsAIActive ~= nil and vehicle:getIsAIActive() or false +end + +function ADCpBridge.start(vehicle, fieldX, fieldZ, onDone) + if not ADCpBridge.isAvailable() then + return nil, "Courseplay (FIELDWORK_CP) findes ikke" + end + local farmId = vehicle:getOwnerFarmId() + local job = g_currentMission.aiJobTypeManager:createJob(AIJobType.FIELDWORK_CP) + if job == nil then return nil, "kunne ikke oprette Courseplay-job" end + job:applyCurrentState(vehicle, g_currentMission, farmId, false, false) + local vx, _, vz = getWorldTranslation(vehicle.rootNode) + local params = job.cpJobParameters + if params ~= nil and params.fieldPosition ~= nil then params.fieldPosition:setPosition(fieldX, fieldZ) end + if params ~= nil and params.startPosition ~= nil then params.startPosition:setPosition(vx, vz) end + job:setValues() + local handle = {cancelled = false, fired = false, finished = false} + local function finish(ok, reason) + if handle.finished then return end + handle.finished = true + if not handle.cancelled then onDone(ok, reason) end + end + local function generateAndStart() + if handle.cancelled then return end + job:onClickGenerateFieldWorkCourse(function(course) + if handle.cancelled then return end + if not course then return finish(false, "Courseplay kunne ikke lave kursus") end + job:setValues() + local ok, err = job:validate(farmId) + if not ok then return finish(false, "Courseplay: " .. tostring(err)) end + g_currentMission.aiSystem:startJob(job, farmId) + finish(true) + end) + end + handle.onBoundary = function(_, success, message) + if handle.fired then return end + handle.fired = true + if handle.cancelled then return end + if not success then return finish(false, "Courseplay fandt ikke markgrænsen: " .. tostring(message)) end + generateAndStart() + end + job:registerFieldBoundaryDetectionCallback(handle, handle.onBoundary) + local isValid, isRunning, message = job:detectFieldBoundary() + if isValid and not isRunning then + generateAndStart() + elseif not isRunning then + return nil, "Courseplay: " .. tostring(message) + end + return handle +end