LUADOC - Farming Simulator 22

AIJobDeliver

Parent
AIJob
Functions

applyCurrentState

Description
Definition
applyCurrentState()
Code
168function AIJobDeliver:applyCurrentState(vehicle, mission, farmId, isDirectStart)
169 AIJobDeliver:superClass().applyCurrentState(self, vehicle, mission, farmId, isDirectStart)
170
171 self.vehicleParameter:setVehicle(vehicle)
172 self.loopingParameter:setIsLooping(true)
173
174 local x, z, angle, _
175 if vehicle.getLastJob ~= nil then
176 local lastJob = vehicle:getLastJob()
177 if lastJob ~= nil and lastJob:isa(AIJobDeliver) then
178 self.unloadingStationParameter:setUnloadingStation(lastJob.unloadingStationParameter:getUnloadingStation())
179 self.loopingParameter:setIsLooping(lastJob.loopingParameter:getIsLooping())
180 x, z = lastJob.positionAngleParameter:getPosition()
181 angle = lastJob.positionAngleParameter:getAngle()
182 end
183 end
184
185 if x == nil or z == nil then
186 x, _, z = getWorldTranslation(vehicle.rootNode)
187 end
188 if angle == nil then
189 local dirX, _, dirZ = localDirectionToWorld(vehicle.rootNode, 0, 0, 1)
190 angle = MathUtil.getYRotationFromDirection(dirX, dirZ)
191 end
192
193 self.positionAngleParameter:setPosition(x, z)
194 self.positionAngleParameter:setAngle(angle)
195
196 local unloadingStations = {}
197 for _, unloadingStation in pairs(g_currentMission.storageSystem:getUnloadingStations()) do
198 if g_currentMission.accessHandler:canPlayerAccess(unloadingStation) and unloadingStation:isa(UnloadingStation) then
199 local fillTypes = unloadingStation:getAISupportedFillTypes()
200 if next(fillTypes) ~= nil then
201 table.insert(unloadingStations, unloadingStation)
202 end
203 end
204 end
205
206 self.unloadingStationParameter:setValidUnloadingStations(unloadingStations)
207end

canContinueWork

Description
Definition
canContinueWork()
Code
344function AIJobDeliver:canContinueWork()
345 local vehicle = self.vehicleParameter:getVehicle()
346 if vehicle == nil then
347 return false, AIMessageErrorVehicleDeleted.new()
348 end
349
350 local unloadingStation = self.unloadingStationParameter:getUnloadingStation()
351 if unloadingStation == nil then
352 return false, AIMessageErrorUnloadingStationDeleted.new()
353 end
354
355 -- check if unloading station is full
356 if self.currentTaskIndex == self.waitForFillingTask.taskIndex then
357 local hasSpace = false
358
359 for _, dischargeNodeInfo in ipairs(self.dischargeNodeInfos) do
360 local dischargeVehicle = dischargeNodeInfo.vehicle
361 local fillUnitIndex = dischargeNodeInfo.dischargeNode.fillUnitIndex
362 if dischargeVehicle:getFillUnitFillLevel(fillUnitIndex) > 1 then
363 local fillTypeIndex = dischargeVehicle:getFillUnitFillType(fillUnitIndex)
364 if unloadingStation:getFreeCapacity(fillTypeIndex, self.startedFarmId) > 0 then
365 hasSpace = true
366 break
367 end
368 end
369 end
370
371 if not hasSpace then
372 return false, AIMessageErrorUnloadingStationFull.new()
373 end
374 end
375
376 return true, nil
377end

getCanSkipTask

Description
Definition
getCanSkipTask()
Code
400function AIJobDeliver:getCanSkipTask()
401 if self.currentTaskIndex == self.waitForFillingTask.taskIndex then
402 if self:getHasLoadedValidFillType() then
403 return true
404 end
405 end
406
407 return false
408end

getDescription

Description
Definition
getDescription()
Code
485function AIJobDeliver:getDescription()
486 local desc = AIJobLoadAndDeliver:superClass().getDescription(self)
487
488 local nextTask = self:getTaskByIndex(self.currentTaskIndex)
489 if nextTask == self.driveToLoadingTask then
490 desc = desc .. " - " .. g_i18n:getText("ai_taskDescriptionDriveToLoadingStation")
491 elseif nextTask == self.waitForFillingTask then
492 desc = desc .. " - " .. g_i18n:getText("ai_taskDescriptionWaitForFilling")
493 elseif nextTask == self.driveToUnloadingTask then
494 desc = desc .. " - " .. g_i18n:getText("ai_taskDescriptionDriveToUnloadingStation")
495 elseif nextTask == self.dischargeTask then
496 desc = desc .. " - " .. g_i18n:getText("ai_taskDescriptionUnloading")
497 end
498
499 return desc
500end

getHasLoadedValidFillType

Description
Definition
getHasLoadedValidFillType()
Code
381function AIJobDeliver:getHasLoadedValidFillType()
382 local unloadingStation = self.unloadingStationParameter:getUnloadingStation()
383
384 for _, dischargeNodeInfo in ipairs(self.dischargeNodeInfos) do
385 local vehicle = dischargeNodeInfo.vehicle
386 local fillUnitIndex = dischargeNodeInfo.dischargeNode.fillUnitIndex
387 if vehicle:getFillUnitFillLevel(fillUnitIndex) > 1 then
388 local fillType = vehicle:getFillUnitFillType(fillUnitIndex)
389 if unloadingStation:getIsFillTypeAISupported(fillType) then
390 return true
391 end
392 end
393 end
394
395 return false
396end

getIsAvailableForVehicle

Description
Definition
getIsAvailableForVehicle()
Code
420function AIJobDeliver:getIsAvailableForVehicle(vehicle)
421 if vehicle.createAgent == nil or vehicle.setAITarget == nil or not vehicle:getCanStartAIVehicle() then
422 return false
423 end
424
425 if vehicle.getAIDischargeNodes ~= nil then
426 local nodes = vehicle:getAIDischargeNodes()
427 if next(nodes) ~= nil then
428 return true
429 end
430 end
431
432 local vehicles = vehicle:getChildVehicles()
433 for _, childVehicle in ipairs(vehicles) do
434 if childVehicle.getAIDischargeNodes ~= nil then
435 local nodes = childVehicle:getAIDischargeNodes()
436 if next(nodes) ~= nil then
437 return true
438 end
439 end
440 end
441end

getIsLooping

Description
Definition
getIsLooping()
Code
456function AIJobDeliver:getIsLooping()
457 return self.loopingParameter:getIsLooping()
458end

getIsStartable

Description
Definition
getIsStartable()
Code
462function AIJobDeliver:getIsStartable(connection)
463 if g_currentMission.aiSystem:getAILimitedReached() then
464 return false, AIJobDeliver.START_ERROR_LIMIT_REACHED
465 end
466
467 local vehicle = self.vehicleParameter:getVehicle()
468 if vehicle == nil then
469 return false, AIJobDeliver.START_ERROR_VEHICLE_DELETED
470 end
471
472 if not g_currentMission:getHasPlayerPermission("hireAssistant", connection, vehicle:getOwnerFarmId()) then
473 return false, AIJobDeliver.START_ERROR_NO_PERMISSION
474 end
475
476 if vehicle:getIsInUse(connection) then
477 return false, AIJobDeliver.START_ERROR_VEHICLE_IN_USE
478 end
479
480 return true, AIJob.START_SUCCESS
481end

getIsStartErrorText

Description
Definition
getIsStartErrorText()
Code
504function AIJobDeliver.getIsStartErrorText(state)
505 if state == AIJobDeliver.START_ERROR_LIMIT_REACHED then
506 return g_i18n:getText("ai_startStateLimitReached")
507 elseif state == AIJobDeliver.START_ERROR_VEHICLE_DELETED then
508 return g_i18n:getText("ai_startStateVehicleDeleted")
509 elseif state == AIJobDeliver.START_ERROR_NO_PERMISSION then
510 return g_i18n:getText("ai_startStateNoPermission")
511 elseif state == AIJobDeliver.START_ERROR_VEHICLE_IN_USE then
512 return g_i18n:getText("ai_startStateVehicleInUse")
513 end
514
515 return g_i18n:getText("ai_startStateSuccess")
516end

getNextTaskIndex

Description
Definition
getNextTaskIndex()
Code
287function AIJobDeliver:getNextTaskIndex(isSkipTask)
288 if self.currentTaskIndex == self.waitForFillingTask.taskIndex or self.currentTaskIndex == self.dischargeTask.taskIndex then
289 local lastUnloadTrigger
290 if self.currentTaskIndex == self.dischargeTask.taskIndex then
291 lastUnloadTrigger = self.dischargeTask.unloadTrigger
292 end
293
294 -- check if there are more dischargeNodes that need discharge to the last unloadtrigger
295 local nextFillType = nil
296 local nextDischargeNodeInfo = nil
297 local unloadingStation = self.unloadingStationParameter:getUnloadingStation()
298 for _, dischargeNodeInfo in ipairs(self.dischargeNodeInfos) do
299 if dischargeNodeInfo.dirty then
300 local vehicle = dischargeNodeInfo.vehicle
301 local fillUnitIndex = dischargeNodeInfo.dischargeNode.fillUnitIndex
302 if vehicle:getFillUnitFillLevel(fillUnitIndex) > 1 then
303 local currentFillType = vehicle:getFillUnitFillType(fillUnitIndex)
304 if lastUnloadTrigger ~= nil and lastUnloadTrigger:getIsFillTypeSupported(currentFillType) then
305 self.dischargeTask:setDischargeNode(vehicle, dischargeNodeInfo.dischargeNode, dischargeNodeInfo.offsetZ)
306 dischargeNodeInfo.dirty = false
307--#debug log("drive to discharge next trailer")
308 return self.currentTaskIndex
309
310 elseif nextFillType == nil then
311 local _, _, _, _, trigger = unloadingStation:getAITargetPositionAndDirection(currentFillType)
312 if trigger ~= nil then
313 nextFillType = currentFillType
314 nextDischargeNodeInfo = dischargeNodeInfo
315 else
316 -- unloading station does not support fill type. mark node as handled
317 dischargeNodeInfo.dirty = false
318 end
319 end
320 end
321 end
322 end
323
324 if nextFillType ~= nil then
325--#debug log("Next index drive to uinloading", g_fillTypeManager:getFillTypeNameByIndex(nextFillType))
326 local x, z, dirX, dirZ, trigger = unloadingStation:getAITargetPositionAndDirection(nextFillType)
327 self.driveToUnloadingTask:setTargetPosition(x, z)
328 self.driveToUnloadingTask:setTargetDirection(dirX, dirZ)
329 self.dischargeTask:setUnloadTrigger(trigger)
330 self.dischargeTask:setDischargeNode(nextDischargeNodeInfo.vehicle, nextDischargeNodeInfo.dischargeNode, nextDischargeNodeInfo.offsetZ)
331 nextDischargeNodeInfo.dirty = false
332
333 return self.driveToUnloadingTask.taskIndex
334 end
335 end
336
337 local nextTaskIndex = AIJobDeliver:superClass().getNextTaskIndex(self, isSkipTask)
338--#debug log("Other: ", self.currentTaskIndex, "->", nextTaskIndex)
339 return nextTaskIndex
340end

getStartTaskIndex

Description
Definition
getStartTaskIndex()
Code
252function AIJobDeliver:getStartTaskIndex()
253 local hasOneEmptyFillUnit = false
254 for _, dischargeNodeInfo in ipairs(self.dischargeNodeInfos) do
255 local vehicle = dischargeNodeInfo.vehicle
256 local fillUnitIndex = dischargeNodeInfo.dischargeNode.fillUnitIndex
257 if vehicle:getFillUnitFillLevel(fillUnitIndex) == 0 then
258 hasOneEmptyFillUnit = true
259 break
260 end
261 end
262
263
264
265 -- check if already at target position
266 local vehicle = self.vehicleParameter:getVehicle()
267 local x, _, z = getWorldTranslation(vehicle.rootNode)
268 local tx, tz = self.positionAngleParameter:getPosition()
269 local targetReached = math.abs(x-tx) < 1 and math.abs(z-tz) < 1
270 if targetReached then
271 if not hasOneEmptyFillUnit then
272 self.waitForFillingTask:skip()
273 end
274 return self.waitForFillingTask.taskIndex
275 end
276
277 if not hasOneEmptyFillUnit then
278 self.driveToLoadingTask:skip()
279 self.waitForFillingTask:skip()
280 end
281
282 return self.driveToLoadingTask.taskIndex
283end

getTitle

Description
Definition
getTitle()
Code
445function AIJobDeliver:getTitle()
446 local vehicle = self.vehicleParameter:getVehicle()
447 if vehicle ~= nil then
448 return vehicle:getName()
449 end
450
451 return ""
452end

new

Description
Definition
new()
Code
22function AIJobDeliver.new(isServer, customMt)
23 local self = AIJob.new(isServer, customMt or AIJobDeliver_mt)
24
25 self.dischargeNodeInfos = {}
26
27 self.driveToLoadingTask = AITaskDriveTo.new(isServer, self)
28 self.waitForFillingTask = AITaskWaitForFilling.new(isServer, self)
29 self.driveToUnloadingTask = AITaskDriveTo.new(isServer, self)
30 self.dischargeTask = AITaskDischarge.new(isServer, self)
31
32 self:addTask(self.driveToLoadingTask)
33 self:addTask(self.waitForFillingTask)
34 self:addTask(self.driveToUnloadingTask)
35 self:addTask(self.dischargeTask)
36
37 self.vehicleParameter = AIParameterVehicle.new()
38 self.unloadingStationParameter = AIParameterUnloadingStation.new()
39 self.loopingParameter = AIParameterLooping.new()
40 self.positionAngleParameter = AIParameterPositionAngle.new(math.rad(5))
41
42 self:addNamedParameter("vehicle", self.vehicleParameter)
43 self:addNamedParameter("unloadingStation", self.unloadingStationParameter)
44 self:addNamedParameter("looping", self.loopingParameter)
45 self:addNamedParameter("positionAngle", self.positionAngleParameter)
46
47 local vehicleGroup = AIParameterGroup.new(g_i18n:getText("ai_parameterGroupTitleVehicle"))
48 vehicleGroup:addParameter(self.vehicleParameter)
49
50 local unloadTargetGroup = AIParameterGroup.new(g_i18n:getText("ai_parameterGroupTitleUnloadingStation"))
51 unloadTargetGroup:addParameter(self.unloadingStationParameter)
52
53 local positionGroup = AIParameterGroup.new(g_i18n:getText("ai_parameterGroupTitleLoadingPosition"))
54 positionGroup:addParameter(self.positionAngleParameter)
55
56 local loopingGroup = AIParameterGroup.new(g_i18n:getText("ai_parameterGroupTitleLooping"))
57 loopingGroup:addParameter(self.loopingParameter)
58
59 table.insert(self.groupedParameters, vehicleGroup)
60 table.insert(self.groupedParameters, unloadTargetGroup)
61 table.insert(self.groupedParameters, positionGroup)
62 table.insert(self.groupedParameters, loopingGroup)
63
64 return self
65end

setValues

Description
Definition
setValues()
Code
69function AIJobDeliver:setValues()
70 self:resetTasks()
71
72 local vehicle = self.vehicleParameter:getVehicle()
73 if vehicle == nil then
74 return
75 end
76 local unloadingStation = self.unloadingStationParameter:getUnloadingStation()
77 if unloadingStation == nil then
78 return
79 end
80
81 self.driveToUnloadingTask:setVehicle(vehicle)
82 self.driveToLoadingTask:setVehicle(vehicle)
83 self.dischargeTask:setVehicle(vehicle)
84 self.waitForFillingTask:setVehicle(vehicle)
85
86 self.dischargeNodeInfos = {}
87
88 -- apply allowed fill types based on unloading trigger
89 for fillType, _ in pairs(unloadingStation:getAISupportedFillTypes()) do
90 self.waitForFillingTask:addAllowedFillType(fillType)
91 end
92
93 if vehicle.getAIDischargeNodes ~= nil then
94 for _, dischargeNode in ipairs(vehicle:getAIDischargeNodes()) do
95
96 local _, _, z = vehicle:getAIDischargeNodeZAlignedOffset(dischargeNode, vehicle)
97 table.insert(self.dischargeNodeInfos, {vehicle=vehicle, dischargeNode=dischargeNode, offsetZ=z, dirty=true})
98 end
99 end
100
101 local childVehicles = vehicle:getChildVehicles()
102 for _, childVehicle in ipairs(childVehicles) do
103 if childVehicle.getAIDischargeNodes ~= nil then
104 for _, dischargeNode in ipairs(childVehicle:getAIDischargeNodes()) do
105 local _, _, z = childVehicle:getAIDischargeNodeZAlignedOffset(dischargeNode, vehicle)
106 table.insert(self.dischargeNodeInfos, {vehicle=childVehicle, dischargeNode=dischargeNode, offsetZ=z, dirty=true})
107 end
108 end
109 end
110
111 table.sort(self.dischargeNodeInfos, function(a, b)
112 return a.offsetZ > b.offsetZ
113 end)
114
115 for _, dischargeNodeInfo in ipairs(self.dischargeNodeInfos) do
116 self.waitForFillingTask:addFillUnits(dischargeNodeInfo.vehicle, dischargeNodeInfo.dischargeNode.fillUnitIndex)
117 end
118
119 local maxOffset = self.dischargeNodeInfos[#self.dischargeNodeInfos].offsetZ
120 self.driveToLoadingTask:setTargetOffset(-maxOffset)
121 self.driveToUnloadingTask:setTargetOffset(-maxOffset)
122
123 local x, z = self.positionAngleParameter:getPosition()
124 if x ~= nil then
125 self.driveToLoadingTask:setTargetPosition(x, z)
126 end
127 local xDir, zDir = self.positionAngleParameter:getDirection()
128 if xDir ~= nil then
129 self.driveToLoadingTask:setTargetDirection(xDir, zDir)
130 end
131end

skipCurrentTask

Description
Definition
skipCurrentTask()
Code
412function AIJobDeliver:skipCurrentTask()
413 if self.currentTaskIndex == self.waitForFillingTask.taskIndex then
414 self.waitForFillingTask:skip()
415 end
416end

start

Description
Definition
start()
Code
211function AIJobDeliver:start(farmId)
212 -- Client start notification will be done by vehicle
213 AIJobDeliver:superClass().start(self, farmId)
214
215 if self.isServer then
216 local vehicle = self.vehicleParameter:getVehicle()
217 vehicle:createAgent(self.helperIndex)
218 vehicle:aiJobStarted(self, self.helperIndex, farmId)
219 end
220end

startTask

Description
Definition
startTask()
Code
239function AIJobDeliver:startTask(task)
240 -- mark all discharge infos as dirty
241 if task == self.waitForFillingTask then
242 for _, dischargeNodeInfo in ipairs(self.dischargeNodeInfos) do
243 dischargeNodeInfo.dirty = true
244 end
245 end
246
247 AIJobDeliver:superClass().startTask(self, task)
248end

stop

Description
Definition
stop()
Code
224function AIJobDeliver:stop(aiMessage)
225 -- Client stop notifcation will be done by vehicle
226 if self.isServer then
227 local vehicle = self.vehicleParameter:getVehicle()
228 vehicle:deleteAgent()
229 vehicle:aiJobFinished()
230 end
231
232 AIJobDeliver:superClass().stop(self, aiMessage)
233
234 self.dischargeNodeInfos = {}
235end

validate

Description
Definition
validate()
Code
135function AIJobDeliver:validate(farmId)
136 self:setParamterValid(true)
137
138 local isVehicleValid, vehicleErrorMessage = self.vehicleParameter:validate()
139 if isVehicleValid then
140 if #self.dischargeNodeInfos == 0 then
141 isVehicleValid = false
142 vehicleErrorMessage = g_i18n:getText("ai_validationErrorNoAIDischargeNodesFound")
143 end
144 end
145 if not isVehicleValid then
146 self.vehicleParameter:setIsValid(false)
147 end
148
149 local isUnloadingStationValid, unloadingStationErrorMessage = self.unloadingStationParameter:validate()
150 if not isUnloadingStationValid then
151 self.unloadingStationParameter:setIsValid(false)
152 end
153
154 local isPositionValid, positionErrorMessage = self.positionAngleParameter:validate()
155 if not isPositionValid then
156 positionErrorMessage = g_i18n:getText("ai_validationErrorNoLoadingPoint")
157 self.positionAngleParameter:setIsValid(false)
158 end
159
160 local isValid = isVehicleValid and isUnloadingStationValid and isPositionValid
161 local errorMessage = vehicleErrorMessage or unloadingStationErrorMessage or positionErrorMessage
162
163 return isValid, errorMessage
164end