Skip to content

Commit bea655f

Browse files
antler22claude
andcommitted
Item 10: re-pathfind when combine relocates during DRIVING_TO_COMBINE
When the combine moves ≥30 m from the position recorded at pathfinding start, trigger a fast A* re-path to its new location. Guards prevent unnecessary stops: - checks only every 5 s - skips if <20 m of course remains (almost there) - skips if already within 25 m of combine (proximity handling takes over) - caps maxIterations at HybridAStar.defaultMaxIterations for speed - excludes the combine from obstacles so the path aims behind it Uses onPathfindingFailedToMovingTarget so a failure is a soft retry, not a job-stopper. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7eea607 commit bea655f

1 file changed

Lines changed: 49 additions & 0 deletions

File tree

scripts/ai/strategies/AIDriveStrategyUnloadCombine.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,12 @@ function AIDriveStrategyUnloadCombine:onPathfindingDoneToWaitingCombine(controll
15731573
self:debug('Pathfinding to waiting combine successful')
15741574
course:adjustForReversing(math.max(1, -AIUtil.getDirectionNodeToReverserNodeOffset(self.vehicle)))
15751575
self:startCourse(course, 1)
1576+
-- Record the combine's position now so driveToCombine() can detect if it has moved
1577+
-- significantly and needs a re-path. Also reset the check timer so the first periodic
1578+
-- check fires 5 s after we start driving, not immediately.
1579+
local cX, _, cZ = getWorldTranslation(self:getPipeOffsetReferenceNode())
1580+
self.combinePositionAtApproachStart = { x = cX, z = cZ }
1581+
self.lastCombinePositionCheckTime = g_time
15761582
self:setNewState(self.states.DRIVING_TO_COMBINE)
15771583
return true
15781584
else
@@ -1966,6 +1972,49 @@ function AIDriveStrategyUnloadCombine:driveToCombine()
19661972

19671973
self:getCombineStrategy():reconfirmRendezvous()
19681974

1975+
-- If the combine has moved significantly since the current approach course was generated,
1976+
-- re-pathfind to its new position so we don't drive to an empty spot.
1977+
-- Guards keep this infrequent and fast:
1978+
-- • only check every 5 s (cheap distance math)
1979+
-- • skip if remaining course < 20 m (almost there — let proximity handling finish)
1980+
-- • skip if already within 25 m of the combine (driveBesideCombine takes over soon)
1981+
-- • only trigger when the combine has actually moved ≥ 30 m (genuine relocation)
1982+
-- Uses a capped iteration count (defaultMaxIterations) so the A* search completes in
1983+
-- well under a second on any field size, minimising the WAITING_FOR_PATHFINDER stop.
1984+
if g_time - (self.lastCombinePositionCheckTime or 0) > 5000 then
1985+
self.lastCombinePositionCheckTime = g_time
1986+
local remainingDist = self.course:getDistanceToLastWaypoint(self.course:getCurrentWaypointIx())
1987+
local distToCombine = self:getDistanceFromCombine()
1988+
if remainingDist > 20 and distToCombine > 25 then
1989+
local cX, _, cZ = getWorldTranslation(self:getPipeOffsetReferenceNode())
1990+
local lastX = self.combinePositionAtApproachStart and self.combinePositionAtApproachStart.x or cX
1991+
local lastZ = self.combinePositionAtApproachStart and self.combinePositionAtApproachStart.z or cZ
1992+
local moved = MathUtil.vector2Length(cX - lastX, cZ - lastZ)
1993+
if moved >= 30 then
1994+
local xOffset, zOffset = self:getPipeOffset(self.combineToUnload)
1995+
zOffset = -self:getCombinesMeasuredBackDistance() - 3
1996+
self:debug('driveToCombine: combine moved %.1f m, re-pathfinding to new position', moved)
1997+
self.combinePositionAtApproachStart = { x = cX, z = cZ }
1998+
-- Fast re-path: cap iterations at the default (avoids multi-second searches on
1999+
-- large fields) and ignore the combine as an obstacle so the path finds the gap
2000+
-- behind it rather than routing around the vehicle body.
2001+
local context = PathfinderContext(self.vehicle)
2002+
context:maxFruitPercent(self:getMaxFruitPercent(self:getPipeOffsetReferenceNode(), xOffset, zOffset))
2003+
context:offFieldPenalty(self:getOffFieldPenalty(self.combineToUnload))
2004+
context:useFieldNum(CpFieldUtil.getFieldNumUnderVehicle(self.combineToUnload))
2005+
context:areaToAvoid(self:getCombineStrategy():getAreaToAvoid())
2006+
context:vehiclesToIgnore({ self.combineToUnload })
2007+
context:maxIterations(HybridAStar.defaultMaxIterations)
2008+
self.pathfinderController:registerListeners(self, self.onPathfindingDoneToWaitingCombine,
2009+
self.onPathfindingFailedToMovingTarget, self.onPathfindingObstacleAtStart)
2010+
self.pathfinderController:findPathToNode(context, self:getPipeOffsetReferenceNode(),
2011+
xOffset or 0, zOffset or 0, 3)
2012+
self:setNewState(self.states.WAITING_FOR_PATHFINDER)
2013+
return
2014+
end
2015+
end
2016+
end
2017+
19692018
-- towards the end of the course we start checking if we can already switch to unload
19702019
if self.course:getDistanceToLastWaypoint(self.course:getCurrentWaypointIx()) < 15 and
19712020
self:isOkToStartUnloadingCombine() then

0 commit comments

Comments
 (0)