From ef1eb0782b7f8188524cf7bd4684bb158ba974b3 Mon Sep 17 00:00:00 2001 From: Peter Vaiko Date: Mon, 20 Jan 2025 06:24:28 -0500 Subject: [PATCH] feat: async field detection in GUI --- config/MasterTranslations.xml | 4 +++ scripts/ai/jobs/CpAIJobFieldWork.lua | 31 ++++++++++++------- scripts/field/FieldBoundaryDetector.lua | 4 +++ scripts/specializations/CpCourseGenerator.lua | 28 ++++++++++++++++- 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml index 9dbd47c6..aeb8eb7c 100644 --- a/config/MasterTranslations.xml +++ b/config/MasterTranslations.xml @@ -47,6 +47,10 @@ + + + + diff --git a/scripts/ai/jobs/CpAIJobFieldWork.lua b/scripts/ai/jobs/CpAIJobFieldWork.lua index ccc8e9c8..cd352e43 100644 --- a/scripts/ai/jobs/CpAIJobFieldWork.lua +++ b/scripts/ai/jobs/CpAIJobFieldWork.lua @@ -109,35 +109,42 @@ function CpAIJobFieldWork:validateFieldSetup() if tx == nil or tz == nil then return false, g_i18n:getText("CP_error_not_on_field") end - if self.fieldPolygonPosition then - if self.fieldPolygonPosition.x == tx and self.fieldPolygonPosition.z == tz then - self.logger:debug(vehicle, 'Field position still at %.1f/%.1f, do not detect field boundary again', tx, tz) - return true, '' - end + if vehicle:cpIsFieldBoundaryDetectionRunning() then + return false, g_i18n:getText("CP_error_field_detection_still_running") + end + local x, z = vehicle:cpGetFieldPosition() + if x == tx and z == tz then + self.logger:debug(vehicle, 'Field position still at %.1f/%.1f, do not detect field boundary again', tx, tz) + return true, '' end self.logger:debug(vehicle, 'Field position changed to %.1f/%.1f, start field boundary detection', tx, tz) self.hasValidPosition = false self.foundVines = nil - local fieldPolygon - fieldPolygon, self.isCustomField = CpFieldUtil.getFieldPolygonAtWorldPosition(tx, tz) + + vehicle:cpDetectFieldBoundary(tx, tz, self, CpAIJobFieldWork.onFieldBoundaryDetectionFinished) + -- TODO: return false and nothing, as the detection is still running? +end + +function CpAIJobFieldWork:onFieldBoundaryDetectionFinished(vehicle, fieldPolygon, islandPolygons) + self:setFieldPolygon(fieldPolygon) if fieldPolygon then self.hasValidPosition = true - self.fieldPolygonPosition = { x = tx, z = tz } - self.foundVines = g_vineScanner:findVineNodesInField(fieldPolygon, tx, tz, self.customField ~= nil) + local x, z = vehicle:cpGetFieldPosition() + self.foundVines = g_vineScanner:findVineNodesInField(fieldPolygon, x, z, self.customField ~= nil) if self.foundVines then CpUtil.debugVehicle(CpDebug.DBG_FIELDWORK, vehicle, "Found vine nodes, generating a vine field border.") - fieldPolygon = g_vineScanner:getCourseGeneratorVertices(0, tx, tz) + fieldPolygon = g_vineScanner:getCourseGeneratorVertices(0, x, z) end self.selectedFieldPlot:setWaypoints(fieldPolygon) self.selectedFieldPlot:setVisible(true) self.selectedFieldPlot:setBrightColor(true) else self.selectedFieldPlot:setVisible(false) + -- TODO: here we need to tell somehow the frame about the detection success/failure return false, g_i18n:getText("CP_error_not_on_field") end - - return true, '' + -- TODO: here we need to tell somehow the frame about the detection success/failure end function CpAIJobFieldWork:setValues() diff --git a/scripts/field/FieldBoundaryDetector.lua b/scripts/field/FieldBoundaryDetector.lua index 09ddbb8b..e9e8c7df 100644 --- a/scripts/field/FieldBoundaryDetector.lua +++ b/scripts/field/FieldBoundaryDetector.lua @@ -45,6 +45,10 @@ function FieldBoundaryDetector:init(x, z, vehicle) self.updates, customField:getName(), x, z) self:_useCustomField(customField) return + else + self.logger:info('Field boundary detection failed after %d updates and no custom field found at %.1f %.1f', + self.updates, x, z) + return end end end) diff --git a/scripts/specializations/CpCourseGenerator.lua b/scripts/specializations/CpCourseGenerator.lua index dd2d7b5f..982c17f8 100644 --- a/scripts/specializations/CpCourseGenerator.lua +++ b/scripts/specializations/CpCourseGenerator.lua @@ -24,6 +24,8 @@ end function CpCourseGenerator.registerFunctions(vehicleType) SpecializationUtil.registerFunction(vehicleType, 'cpDetectFieldBoundary', CpCourseGenerator.cpDetectFieldBoundary) + SpecializationUtil.registerFunction(vehicleType, 'cpIsFieldBoundaryDetectionRunning', CpCourseGenerator.cpIsFieldBoundaryDetectionRunning) + SpecializationUtil.registerFunction(vehicleType, 'cpGetFieldPosition', CpCourseGenerator.cpGetFieldPosition) SpecializationUtil.registerFunction(vehicleType, 'cpGetFieldPolygon', CpCourseGenerator.cpGetFieldPolygon) SpecializationUtil.registerFunction(vehicleType, 'cpDrawFieldPolygon', CpCourseGenerator.cpDrawFieldPolygon) end @@ -31,6 +33,9 @@ end function CpCourseGenerator:onLoad(savegame) -- create shortcut to this spec self.spec_cpCourseGenerator = self["spec_" .. CpCourseGenerator.SPEC_NAME] + self.spec_cpCourseGenerator.logger = Logger(CpCourseGenerator.SPEC_NAME, nil, CpDebug.DBG_COURSES) + -- make sure cpGetFieldPosition always returns at least an empty table + self.spec_cpCourseGenerator.position = {} end ---@param x number world X coordinate to start the detection at @@ -39,9 +44,29 @@ end ---@param onFinishedFunc function callback function to call when finished: onFinishedFunc([object,] vehicle, fieldPolygon, islandPolygons) function CpCourseGenerator:cpDetectFieldBoundary(x, z, object, onFinishedFunc) local spec = self.spec_cpCourseGenerator - spec.fieldBoundaryDetector = FieldBoundaryDetector(x, z, self) + if spec.isFieldBoundaryDetectionRunning then + self.logger:warning(self, 'Not starting field boundary detection for %.1f/%.1f, previous for %.1f/%.1f is still running', + x, z, spec.position.x, spec.position.z) + return + end + spec.position = { x = x, z = z } spec.object = object spec.onFinishedFunc = onFinishedFunc + spec.fieldBoundaryDetector = FieldBoundaryDetector(x, z, self) + spec.isFieldBoundaryDetectionRunning = true +end + +---@return boolean true if field boundary detection is running. Field and island polygons returned while running may +--- be nil or invalid. +function CpCourseGenerator:cpIsFieldBoundaryDetectionRunning() + return self.spec_cpCourseGenerator.isFieldBoundaryDetectionRunning +end + +---@return number|nil, number|nil world X and Z coordinates of the last field boundary detection start position, nil +--- if no previous detection was started +function CpCourseGenerator:cpGetFieldPosition() + local spec = self.spec_cpCourseGenerator + return spec.position.x, spec.position.z end function CpCourseGenerator:onUpdate(dt) @@ -49,6 +74,7 @@ function CpCourseGenerator:onUpdate(dt) if spec.fieldBoundaryDetector then if not spec.fieldBoundaryDetector:update(dt) then -- done + spec.isFieldBoundaryDetectionRunning = false spec.fieldPolygon = spec.fieldBoundaryDetector:getFieldPolygon() spec.islandPolygons = spec.fieldBoundaryDetector:getIslandPolygons() spec.fieldBoundaryDetector = nil