diff --git a/config/InfoTexts.xml b/config/InfoTexts.xml
index 3133e3c8..39c1394a 100644
--- a/config/InfoTexts.xml
+++ b/config/InfoTexts.xml
@@ -24,6 +24,7 @@
+
@@ -41,4 +42,5 @@
+
\ No newline at end of file
diff --git a/config/MasterTranslations.xml b/config/MasterTranslations.xml
index aeb8eb7c..f0cb2157 100644
--- a/config/MasterTranslations.xml
+++ b/config/MasterTranslations.xml
@@ -71,10 +71,6 @@
-
-
-
-
@@ -389,6 +385,10 @@
+
+
+
+
@@ -1724,6 +1724,10 @@ The course is saved automatically on closing of the editor and overrides the sel
+
+
+
+
diff --git a/scripts/Course.lua b/scripts/Course.lua
index 09bcf215..39adf18b 100644
--- a/scripts/Course.lua
+++ b/scripts/Course.lua
@@ -76,22 +76,6 @@ function Course:getVehicle()
return self.vehicle
end
-function Course:setFieldPolygon(polygon)
- self.fieldPolygon = polygon
-end
-
--- The field polygon used to generate the course
-function Course:getFieldPolygon()
- local i = 1
- while self.fieldPolygon == nil and i < self:getNumberOfWaypoints() do
- CpUtil.debugVehicle(CpDebug.DBG_COURSES, self.vehicle, 'Field polygon not found, regenerating it (%d).', i)
- local px, _, pz = self:getWaypointPosition(i)
- self.fieldPolygon = CpFieldUtil.getFieldPolygonAtWorldPosition(px, pz)
- i = i + 1
- end
- return self.fieldPolygon
-end
-
function Course:getName()
return self.name
end
diff --git a/scripts/ai/AIMessages.lua b/scripts/ai/AIMessages.lua
index a7563f0e..7e69409a 100644
--- a/scripts/ai/AIMessages.lua
+++ b/scripts/ai/AIMessages.lua
@@ -54,6 +54,13 @@ function AIMessageErrorWrongMissionFruitType:getI18NText()
return g_i18n:getText("CP_ai_messageErrorWrongMissionFruitType")
end
+---@class AIMessageErrorTooFarFromField
+AIMessageErrorTooFarFromField = CpObject(AIMessage, AIMessage.new)
+AIMessageErrorTooFarFromField.name = "CP_ERROR_TOO_FAR_FROM_FIELD"
+function AIMessageErrorTooFarFromField:getI18NText()
+ return g_i18n:getText("CP_ai_messageErrorTooFarFromField")
+end
+
CpAIMessages = {}
function CpAIMessages.register()
local function register(messageClass)
@@ -67,6 +74,7 @@ function CpAIMessages.register()
register(AIMessageErrorCutterNotSupported)
register(AIMessageErrorAutomaticCutterAttachNotActive)
register(AIMessageErrorWrongMissionFruitType)
+ register(AIMessageErrorTooFarFromField)
end
--- Another ugly hack, as the giants code to get the message index in mp isn't working ..
diff --git a/scripts/ai/jobs/CpAIJob.lua b/scripts/ai/jobs/CpAIJob.lua
index f9ac15b9..bb981306 100644
--- a/scripts/ai/jobs/CpAIJob.lua
+++ b/scripts/ai/jobs/CpAIJob.lua
@@ -248,6 +248,38 @@ function CpAIJob:validate(farmId)
return isValid, errorMessage
end
+--- Start an asynchronous field boundary detection. Results are delivered by the callback
+--- onFieldBoundaryDetectionFinished(vehicle, fieldPolygon, islandPolygons)
+--- If the field position hasn't changed since the last call, the detection is skipped and this returns true.
+--- In that case, the polygon from the previous run is still available from vehicle:cpGetFieldPolygon()
+---@return boolean, string TODO
+function CpAIJob:detectFieldBoundary()
+ local vehicle = self.vehicleParameter:getVehicle()
+
+ local tx, tz = self.cpJobParameters.fieldPosition:getPosition()
+ if tx == nil or tz == nil then
+ return false, g_i18n:getText("CP_error_not_on_field")
+ 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:debug('Field position still at %.1f/%.1f, do not detect field boundary again', tx, tz)
+ return true, ''
+ end
+ self:debug('Field position changed to %.1f/%.1f, start field boundary detection', tx, tz)
+ self.foundVines = nil
+
+ vehicle:cpDetectFieldBoundary(tx, tz, self, self.onFieldBoundaryDetectionFinished)
+ -- TODO: return false and nothing, as the detection is still running?
+ return true, g_i18n:getText('CP_error_field_detection_still_running')
+end
+
+function CpAIJob:onFieldBoundaryDetectionFinished(vehicle, fieldPolygon, islandPolygons)
+ -- override in the derived classes to handle the detected field boundary
+end
+
function CpAIJob:getIsStartable(connection)
local vehicle = self.vehicleParameter:getVehicle()
diff --git a/scripts/ai/jobs/CpAIJobBaleFinder.lua b/scripts/ai/jobs/CpAIJobBaleFinder.lua
index 45aa7215..4f311ea7 100644
--- a/scripts/ai/jobs/CpAIJobBaleFinder.lua
+++ b/scripts/ai/jobs/CpAIJobBaleFinder.lua
@@ -4,7 +4,6 @@
CpAIJobBaleFinder = CpObject(CpAIJob)
CpAIJobBaleFinder.name = "BALE_FINDER_CP"
CpAIJobBaleFinder.jobName = "CP_job_baleCollect"
-CpAIJobBaleFinder.minStartDistanceToField = 20
function CpAIJobBaleFinder:init(isServer)
CpAIJob.init(self, isServer)
self.selectedFieldPlot = FieldPlot(true)
@@ -28,10 +27,9 @@ function CpAIJobBaleFinder:getIsAvailableForVehicle(vehicle, cpJobsAllowed)
end
function CpAIJobBaleFinder:getCanStartJob()
- return self:getFieldPolygon() ~= nil
+ return self:getVehicle():cpGetFieldPolygon() ~= nil
end
-
function CpAIJobBaleFinder:applyCurrentState(vehicle, mission, farmId, isDirectStart, isStartPositionInvalid)
CpAIJob.applyCurrentState(self, vehicle, mission, farmId, isDirectStart)
self.cpJobParameters:validateSettings()
@@ -64,43 +62,11 @@ function CpAIJobBaleFinder:validate(farmId)
--------------------------------------------------------------
--- Validate field setup
--------------------------------------------------------------
-
- isValid, errorMessage = self:validateFieldPosition(isValid, errorMessage)
- local fieldPolygon = self:getFieldPolygon()
- --------------------------------------------------------------
- --- Validate start distance to field, if started with the hud
- --------------------------------------------------------------
- if isValid and self.isDirectStart and fieldPolygon then
- --- Checks the distance for starting with the hud, as a safety check.
- --- Firstly check, if the vehicle is near the field.
- local x, _, z = getWorldTranslation(vehicle.rootNode)
- isValid = CpMathUtil.isPointInPolygon(fieldPolygon, x, z) or
- CpMathUtil.getClosestDistanceToPolygonEdge(fieldPolygon, x, z) < self.minStartDistanceToField
- if not isValid then
- return false, g_i18n:getText("CP_error_vehicle_too_far_away_from_field")
- end
- end
-
+ isValid, errorMessage = self:detectFieldBoundary(isValid, errorMessage)
return isValid, errorMessage
end
-function CpAIJobBaleFinder:validateFieldPosition(isValid, errorMessage)
- local tx, tz = self.cpJobParameters.fieldPosition:getPosition()
- if tx == nil or tz == nil then
- return false, g_i18n:getText("CP_error_not_on_field")
- end
- local fieldPolygon, _ = CpFieldUtil.getFieldPolygonAtWorldPosition(tx, tz)
- self:setFieldPolygon(fieldPolygon)
- if fieldPolygon then
- self.selectedFieldPlot:setWaypoints(fieldPolygon)
- self.selectedFieldPlot:setVisible(true)
- else
- return false, g_i18n:getText("CP_error_not_on_field")
- end
- return isValid, errorMessage
-end
-
function CpAIJobBaleFinder:draw(map, isOverviewMap)
CpAIJob.draw(self, map, isOverviewMap)
if not isOverviewMap then
diff --git a/scripts/ai/jobs/CpAIJobFieldWork.lua b/scripts/ai/jobs/CpAIJobFieldWork.lua
index cd352e43..4d34981d 100644
--- a/scripts/ai/jobs/CpAIJobFieldWork.lua
+++ b/scripts/ai/jobs/CpAIJobFieldWork.lua
@@ -10,11 +10,10 @@ CpAIJobFieldWork.jobName = "CP_job_fieldWork"
CpAIJobFieldWork.GenerateButton = "FIELDWORK_BUTTON"
function CpAIJobFieldWork:init(isServer)
CpAIJob.init(self, isServer)
- self.logger = Logger('CpAIJobFieldWork', nil, CpDebug.DBG_FIELDWORK)
- self.hasValidPosition = false
self.foundVines = nil
self.selectedFieldPlot = FieldPlot(true)
self.selectedFieldPlot:setVisible(false)
+ self.selectedFieldPlot:setBrightColor(true)
self.courseGeneratorInterface = CourseGeneratorInterface()
end
@@ -77,7 +76,6 @@ end
---@param isDirectStart boolean disables the drive to by giants
---@param resetToVehiclePosition boolean resets the drive to target position by giants and the field position to the vehicle position.
function CpAIJobFieldWork:applyCurrentState(vehicle, mission, farmId, isDirectStart, resetToVehiclePosition)
- print('********************** Apply current state **********************')
CpAIJob.applyCurrentState(self, vehicle, mission, farmId, isDirectStart)
if resetToVehiclePosition then
-- set the start and the field position to the vehicle's position (
@@ -97,39 +95,16 @@ function CpAIJobFieldWork:applyCurrentState(vehicle, mission, farmId, isDirectSt
self.cpJobParameters.fieldPosition:setPosition(x, z)
end
end
-end
-
---- Checks the field position setting.
-function CpAIJobFieldWork:validateFieldSetup()
- print('********************** Validate field setup **********************')
- local vehicle = self.vehicleParameter:getVehicle()
-
- -- everything else is valid, now find the field
- local tx, tz = self.cpJobParameters.fieldPosition:getPosition()
- if tx == nil or tz == nil then
- return false, g_i18n:getText("CP_error_not_on_field")
- 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, ''
+ local fieldPolygon = vehicle:cpGetFieldPolygon()
+ if fieldPolygon then
+ -- if we already have a field polygon, show it
+ self.selectedFieldPlot:setWaypoints(fieldPolygon)
+ self.selectedFieldPlot:setVisible(true)
end
- self.logger:debug(vehicle, 'Field position changed to %.1f/%.1f, start field boundary detection', tx, tz)
- self.hasValidPosition = false
- self.foundVines = nil
-
- 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
local x, z = vehicle:cpGetFieldPosition()
self.foundVines = g_vineScanner:findVineNodesInField(fieldPolygon, x, z, self.customField ~= nil)
if self.foundVines then
@@ -138,7 +113,6 @@ function CpAIJobFieldWork:onFieldBoundaryDetectionFinished(vehicle, fieldPolygon
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
@@ -167,7 +141,7 @@ function CpAIJobFieldWork:validate(farmId)
--- Only check the valid field position in the in game menu.
if not self.isDirectStart then
- isValid, errorMessage = self:validateFieldSetup()
+ isValid, errorMessage = self:detectFieldBoundary()
if not isValid then
return isValid, errorMessage
end
@@ -190,7 +164,8 @@ function CpAIJobFieldWork:draw(map, isOverviewMap)
end
function CpAIJobFieldWork:getCanGenerateFieldWorkCourse()
- return self.hasValidPosition
+ local vehicle = self:getVehicle()
+ return vehicle and vehicle:cpGetFieldPolygon() ~= nil and not vehicle:cpIsFieldBoundaryDetectionRunning()
end
-- To pass an alignment course from the drive to fieldwork start to the fieldwork, so the
diff --git a/scripts/ai/strategies/AIDriveStrategyCombineCourse.lua b/scripts/ai/strategies/AIDriveStrategyCombineCourse.lua
index 2d3816d2..9849a75d 100644
--- a/scripts/ai/strategies/AIDriveStrategyCombineCourse.lua
+++ b/scripts/ai/strategies/AIDriveStrategyCombineCourse.lua
@@ -122,6 +122,14 @@ function AIDriveStrategyCombineCourse:getStateAsString()
return s
end
+--- Combine needs a field polygon for the self-unload to work. Although it is a user setting, but it can be
+--- changed during the work, so we always require the field polygon, regardless of the setting, as it is checked
+--- only after starting the CP driver.
+---@return boolean true if the strategy needs the field polygon to work
+function AIDriveStrategyCombineCourse:needsFieldPolygon()
+ return true
+end
+
-----------------------------------------------------------------------------------------------------------------------
--- Initialization
-----------------------------------------------------------------------------------------------------------------------
diff --git a/scripts/ai/strategies/AIDriveStrategyCourse.lua b/scripts/ai/strategies/AIDriveStrategyCourse.lua
index 7bd9f5c9..febd8f49 100644
--- a/scripts/ai/strategies/AIDriveStrategyCourse.lua
+++ b/scripts/ai/strategies/AIDriveStrategyCourse.lua
@@ -25,6 +25,7 @@ AIDriveStrategyCourse = CpObject()
AIDriveStrategyCourse.myStates = {
INITIAL = {},
WAITING_FOR_PATHFINDER = {},
+ WAITING_FOR_FIELD_BOUNDARY_DETECTION = {},
}
--- Implement controller events.
@@ -703,4 +704,32 @@ function AIDriveStrategyCourse:updateInfoTexts()
self:clearInfoText(infoText)
end
end
-end
\ No newline at end of file
+end
+
+------------------------------------------------------------------------------------------------------------------------
+--- Field boundary detection
+---------------------------------------------------------------------------------------------------------------------------
+--- Some strategies need to know the field boundaries. Bale finder must search for bales on the field, combine
+--- unload will look for harvesters on the field, self-unload will look for trailers around the field. When
+--- these strategies are started directly from the HUD or by a shortcut, they won't necessarily have a the
+--- field boundary yet, as detection is an asynchronous process. Once the detection is done, the field polygon is
+--- available in the CpCourseGenerator specialization by calling cpGetFieldPolygon().
+---
+--- Strategies that need the boundary should set the state WAITING_FOR_FIELD_BOUNDARY_DETECTION and call this on
+--- until it returns true and only then transition to the INITIAL state.
+---
+---@return boolean true if the field boundary is already available
+function AIDriveStrategyCourse:haveFieldPolygon()
+ if self.fieldPolygon == nil then
+ if self.vehicle:cpGetFieldPolygon() then
+ self:clearInfoText(InfoTextManager.WAITING_FOR_FIELD_BOUNDARY_DETECTION)
+ self.fieldPolygon = self.vehicle:cpGetFieldPolygon()
+ return true
+ else
+ self:setInfoText(InfoTextManager.WAITING_FOR_FIELD_BOUNDARY_DETECTION)
+ return false
+ end
+ else
+ return true
+ end
+end
diff --git a/scripts/ai/strategies/AIDriveStrategyFieldWorkCourse.lua b/scripts/ai/strategies/AIDriveStrategyFieldWorkCourse.lua
index 281b018c..83bd1009 100644
--- a/scripts/ai/strategies/AIDriveStrategyFieldWorkCourse.lua
+++ b/scripts/ai/strategies/AIDriveStrategyFieldWorkCourse.lua
@@ -94,12 +94,27 @@ function AIDriveStrategyFieldWorkCourse:start(course, startIx, jobParameters)
--- Store a reference to the original generated course
self.originalGeneratedFieldWorkCourse = self.vehicle:getFieldWorkCourse()
- if self.fieldPolygon == nil then
- self:debug("No field polygon received, so regenerate it by the course.")
- self.fieldPolygon = self.fieldWorkCourse:getFieldPolygon()
+ if self:needsFieldPolygon() then
+ self.fieldPolygon = self.vehicle:cpGetFieldPolygon()
+ if self.fieldPolygon == nil then
+ self:debug("Need field boundary to work, start detection now.")
+ -- TODO: should really store the field position (or the polygon itself?) with the course, as
+ -- in some rare cases, for instance when using field margin, the start waypoint may be outside
+ -- of the field, and thus the detection won't work.
+ local x, _, z = self.fieldWorkCourse:getWaypointPosition(startIx)
+ -- no callback, haveFieldPolygon() will take care of the result
+ self.vehicle:cpDetectFieldBoundary(x, z)
+ end
end
end
+--- If the strategy needs a field polygon to work, it won't transition out of the INITIAL state
+--- until the field detection, an asynchronous process that may have started only when the job was started, is finished.
+---@return boolean true if the strategy needs the field polygon to work
+function AIDriveStrategyFieldWorkCourse:needsFieldPolygon()
+ return false
+end
+
--- Make sure all implements are in the working state
function AIDriveStrategyFieldWorkCourse:prepareForFieldWork()
self.vehicle:raiseAIEvent('onAIFieldWorkerPrepareForWork', 'onAIImplementPrepareForWork')
@@ -163,8 +178,11 @@ function AIDriveStrategyFieldWorkCourse:getDriveData(dt, vX, vY, vZ)
----------------------------------------------------------------
if self.state == self.states.INITIAL then
self:setMaxSpeed(0)
- self:startWaitingForLower()
- self:lowerImplements()
+ if not self:needsFieldPolygon() or (self:needsFieldPolygon() and self:haveFieldPolygon()) then
+ -- continue only if we have the field polygon, if we need it.
+ self:startWaitingForLower()
+ self:lowerImplements()
+ end
elseif self.state == self.states.WAITING_FOR_LOWER then
self:setMaxSpeed(0)
if self:getCanContinueWork() then
@@ -755,10 +773,6 @@ function AIDriveStrategyFieldWorkCourse:setAllStaticParameters()
self.fieldWorkerProximityController = FieldWorkerProximityController(self.vehicle, self.workWidth)
end
-function AIDriveStrategyFieldWorkCourse:setFieldPolygon(polygon)
- self.fieldPolygon = polygon
-end
-
-----------------------------------------------------------------------------------------------------------------------
--- Dynamic parameters (may change while driving)
-----------------------------------------------------------------------------------------------------------------------
diff --git a/scripts/ai/strategies/AIDriveStrategyFindBales.lua b/scripts/ai/strategies/AIDriveStrategyFindBales.lua
index d349c839..56c64b66 100644
--- a/scripts/ai/strategies/AIDriveStrategyFindBales.lua
+++ b/scripts/ai/strategies/AIDriveStrategyFindBales.lua
@@ -36,6 +36,7 @@ AIDriveStrategyFindBales.myStates = {
}
--- Offset to apply at the goal marker, so we don't crash with an empty unloader waiting there with the same position.
AIDriveStrategyFindBales.invertedGoalPositionOffset = -4.5
+AIDriveStrategyFindBales.minStartDistanceToField = 20
function AIDriveStrategyFindBales:init(task, job)
AIDriveStrategyCourse.init(self, task, job)
@@ -183,32 +184,11 @@ function AIDriveStrategyFindBales:setAllStaticParameters()
self.numBalesLeftOver = 0
end
-function AIDriveStrategyFindBales:setFieldPolygon(fieldPolygon)
- self.fieldPolygon = fieldPolygon
-end
-
--- Bale wrap type for the bale loader.
function AIDriveStrategyFindBales:setAIVehicle(vehicle, jobParameters)
AIDriveStrategyCourse.setAIVehicle(self, vehicle, jobParameters)
self.baleWrapType = jobParameters.baleWrapType:getValue()
self:debug("Bale type selected: %s", tostring(self.baleWrapType))
-
- local x, z = jobParameters.startPosition:getPosition()
- local angle = jobParameters.startPosition:getAngle()
- if x ~= nil and z ~= nil and angle ~= nil then
- --- Additionally safety check, if the position is on the field or near it.
- if CpMathUtil.isPointInPolygon(self.fieldPolygon, x, z)
- or CpMathUtil.getClosestDistanceToPolygonEdge(self.fieldPolygon, x, z) < 2 * CpAIJobBaleFinder.minStartDistanceToField then
- --- Goal position marker set in the ai menu rotated by 180 degree.
- self.invertedStartPositionMarkerNode = CpUtil.createNode("Inverted Start position marker",
- x, z, angle + math.pi)
- self:debug("Valid goal position marker was set.")
- else
- self:debug("Start position is too far away from the field for a valid goal position!")
- end
- else
- self:debug("Invalid start position found!")
- end
end
-----------------------------------------------------------------------------------------------------------------------
--- Bale finding
@@ -536,7 +516,7 @@ end
function AIDriveStrategyFindBales:getDriveData(dt, vX, vY, vZ)
self:updateLowFrequencyImplementControllers()
self:updateLowFrequencyPathfinder()
- if self.state == self.states.INITIAL then
+ if self.state == self.states.INITIAL and self:isPositionOk() then
if self:getCanContinueWork() then
self.state = self.states.SEARCHING_FOR_NEXT_BALE
else
@@ -607,6 +587,46 @@ function AIDriveStrategyFindBales:approachBale()
end
end
+--- Check if we have the field polygon (as we need it to find the bales) and if we are on or close to the field.
+--- The field polygon generation is started by the job and if we direct start, may not have finished yet.
+--- Once we have it, check the vehicle and start positions.
+function AIDriveStrategyFindBales:isPositionOk()
+ if self:haveFieldPolygon() then
+ if not self.positionChecked then
+ self.positionChecked = true
+ --- check, if the vehicle is near the field.
+ local x, _, z = getWorldTranslation(self.vehicle.rootNode)
+ if CpMathUtil.isPointInPolygon(self.fieldPolygon, x, z) or
+ CpMathUtil.getClosestDistanceToPolygonEdge(self.fieldPolygon, x, z) < AIDriveStrategyFindBales.minStartDistanceToField then
+ -- now check the start position
+ x, z = self.jobParameters.startPosition:getPosition()
+ local angle = self.jobParameters.startPosition:getAngle()
+ if x ~= nil and z ~= nil and angle ~= nil then
+ --- Additionally safety check, if the position is on the field or near it.
+ if CpMathUtil.isPointInPolygon(self.fieldPolygon, x, z)
+ or CpMathUtil.getClosestDistanceToPolygonEdge(self.fieldPolygon, x, z) < 2 * AIDriveStrategyFindBales.minStartDistanceToField then
+ --- Goal position marker set in the ai menu rotated by 180 degree.
+ self.invertedStartPositionMarkerNode = CpUtil.createNode("Inverted Start position marker",
+ x, z, angle + math.pi)
+ self:debug("Valid goal position marker was set.")
+ else
+ self:debug("Start position is too far away from the field for a valid goal position!")
+ end
+ else
+ self:debug("Invalid start position found!")
+ end
+ else
+ self:debug('Vehicle not on field or too far away from field')
+ self.vehicle:stopCurrentAIJob(AIMessageErrorTooFarFromField.new())
+ return false
+ end
+ end
+ return true
+ else
+ return false
+ end
+end
+
function AIDriveStrategyFindBales:workOnBale()
if self.baleLoader then
if self:isReadyToLoadNextBale() then
diff --git a/scripts/ai/tasks/CpAITaskBaleFinder.lua b/scripts/ai/tasks/CpAITaskBaleFinder.lua
index db650c8f..7e486e6b 100644
--- a/scripts/ai/tasks/CpAITaskBaleFinder.lua
+++ b/scripts/ai/tasks/CpAITaskBaleFinder.lua
@@ -1,12 +1,11 @@
----@class CpAIJobBaleFinder : CpAITask
+---@class CpAITaskBaleFinder : CpAITask
CpAITaskBaleFinder = CpObject(CpAITask)
function CpAITaskBaleFinder:start()
if self.isServer then
self:debug("CP bale finder task started.")
local strategy = AIDriveStrategyFindBales(self, self.job)
- strategy:setFieldPolygon(self.job:getFieldPolygon())
strategy:setAIVehicle(self.vehicle, self.job:getCpJobParameters())
self.vehicle:startCpWithStrategy(strategy)
end
diff --git a/scripts/ai/tasks/CpAITaskFieldWork.lua b/scripts/ai/tasks/CpAITaskFieldWork.lua
index e5a0d562..dc561d87 100644
--- a/scripts/ai/tasks/CpAITaskFieldWork.lua
+++ b/scripts/ai/tasks/CpAITaskFieldWork.lua
@@ -76,7 +76,7 @@ function CpAITaskFieldWork:start()
--- Remembers the last lane offset setting value that was used.
cpSpec.cpJobStartAtLastWp:getCpJobParameters().laneOffset:setValue(self.job:getCpJobParameters().laneOffset:getValue())
if spec.driveStrategies ~= nil then
- -- This deltition code could be removed, but just to be sure we let it stay here for now.
+ -- This deletion code could be removed, but just to be sure we let it stay here for now.
for i = #spec.driveStrategies, 1, -1 do
spec.driveStrategies[i]:delete()
table.remove(spec.driveStrategies, i)
@@ -105,7 +105,6 @@ function CpAITaskFieldWork:start()
cpDriveStrategy = AIDriveStrategyFieldWorkCourse(self, self.job)
end
end
- cpDriveStrategy:setFieldPolygon(self.job:getFieldPolygon())
cpDriveStrategy:setAIVehicle(self.vehicle, self.job:getCpJobParameters())
cpSpec.driveStrategy = cpDriveStrategy
--- Only the last driving strategy can stop the helper, while it is running.
diff --git a/scripts/courseGenerator/CourseGeneratorInterface.lua b/scripts/courseGenerator/CourseGeneratorInterface.lua
index 25e8f3c8..83622374 100644
--- a/scripts/courseGenerator/CourseGeneratorInterface.lua
+++ b/scripts/courseGenerator/CourseGeneratorInterface.lua
@@ -166,7 +166,6 @@ function CourseGeneratorInterface:generate(fieldPolygon,
local course = Course.createFromGeneratedCourse(vehicle, self.generatedCourse,
settings.workWidth:getValue(), numberOfHeadlands, settings.multiTools:getValue(),
settings.headlandClockwise:getValue(), settings.islandHeadlandClockwise:getValue(), not settings.useBaseLineEdge:getValue())
- course:setFieldPolygon(fieldPolygon)
self:setCourse(vehicle, course)
return true, course
end
@@ -228,7 +227,6 @@ function CourseGeneratorInterface:generateVineCourse(
local course = Course.createFromGeneratedCourse(vehicle, self.generatedCourse,
workWidth, 0, multiTools, true, true, true)
- course:setFieldPolygon(fieldPolygon)
self:setCourse(vehicle, course)
return true, course
end
diff --git a/scripts/specializations/CpCourseGenerator.lua b/scripts/specializations/CpCourseGenerator.lua
index 982c17f8..45643125 100644
--- a/scripts/specializations/CpCourseGenerator.lua
+++ b/scripts/specializations/CpCourseGenerator.lua
@@ -20,6 +20,8 @@ end
function CpCourseGenerator.registerEventListeners(vehicleType)
SpecializationUtil.registerEventListener(vehicleType, "onUpdate", CpCourseGenerator)
SpecializationUtil.registerEventListener(vehicleType, "onLoad", CpCourseGenerator)
+ SpecializationUtil.registerEventListener(vehicleType, "onReadStream", CpCourseGenerator)
+ SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", CpCourseGenerator)
end
function CpCourseGenerator.registerFunctions(vehicleType)
@@ -45,7 +47,7 @@ end
function CpCourseGenerator:cpDetectFieldBoundary(x, z, object, onFinishedFunc)
local spec = self.spec_cpCourseGenerator
if spec.isFieldBoundaryDetectionRunning then
- self.logger:warning(self, 'Not starting field boundary detection for %.1f/%.1f, previous for %.1f/%.1f is still running',
+ spec.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
@@ -78,10 +80,12 @@ function CpCourseGenerator:onUpdate(dt)
spec.fieldPolygon = spec.fieldBoundaryDetector:getFieldPolygon()
spec.islandPolygons = spec.fieldBoundaryDetector:getIslandPolygons()
spec.fieldBoundaryDetector = nil
- if spec.object then
+ if spec.object and spec.onFinishedFunc then
spec.onFinishedFunc(spec.object, self, spec.fieldPolygon, spec.islandPolygons)
- else
+ elseif spec.onFinishedFunc then
spec.onFinishedFunc(self, spec.fieldPolygon, spec.islandPolygons)
+ else
+ spec.logger:debug('Field boundary detection finished, but no callback given')
end
end
end
@@ -110,3 +114,33 @@ function CpCourseGenerator:cpDrawFieldPolygon()
end
end
end
+
+function CpCourseGenerator:onReadStream(streamId, connection)
+ local spec = self.spec_cpCourseGenerator
+ local numVertices = streamReadInt32(streamId)
+ if numVertices == 0 then
+ spec.fieldPolygon = nil
+ else
+ spec.fieldPolygon = {}
+ for _ = 1, numVertices do
+ local x = streamReadFloat32(streamId)
+ local y = streamReadFloat32(streamId)
+ local z = streamReadFloat32(streamId)
+ table.insert(spec.fieldPolygon, { x = x, y = y, z = z })
+ end
+ end
+end
+
+function CpCourseGenerator:onWriteStream(streamId, connection)
+ local spec = self.spec_cpCourseGenerator
+ if spec.fieldPolygon then
+ streamWriteInt32(streamId, #spec.fieldPolygon)
+ for _, point in pairs(spec.fieldPolygon) do
+ streamWriteFloat32(streamId, point.x)
+ streamWriteFloat32(streamId, point.y)
+ streamWriteFloat32(streamId, point.z)
+ end
+ else
+ streamWriteInt32(streamId, 0)
+ end
+end
\ No newline at end of file