LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

CropSensor

Description
Specialization for crop sensors
Functions

actionControllerToggleEvent

Description
Definition
actionControllerToggleEvent()
Code
305function CropSensor.actionControllerToggleEvent(self, direction)
306 self:setCropSensorActive(direction >= 0)
307
308 return true
309end

actionEventToggle

Description
Definition
actionEventToggle()
Code
289function CropSensor.actionEventToggle(self, actionName, inputValue, callbackState, isAnalog)
290 self:setCropSensorActive()
291end

doCheckSpeedLimit

Description
Returns if speed limit should be checked
Definition
doCheckSpeedLimit()
Return Values
booleancheckSpeedlimitcheck speed limit
Code
314function CropSensor:doCheckSpeedLimit(superFunc)
315 return superFunc(self) or (self.spec_cropSensor ~= nil and self.spec_cropSensor.isStandaloneSensor and self.spec_cropSensor.isActive)
316end

getMaxWorkingWidth

Description
Definition
getMaxWorkingWidth()
Code
467function CropSensor.getMaxWorkingWidth(sensorVehicle)
468 local childVehicles = sensorVehicle.rootVehicle.childVehicles
469
470 local maxWidth = 0
471
472 for i=1, #childVehicles do
473 local childVehicle = childVehicles[i]
474 if SpecializationUtil.hasSpecialization(ExtendedSprayer, childVehicle.specializations) then
475 if childVehicle.getWorkAreaByIndex ~= nil then
476 local workAreas = childVehicle.spec_workArea.workAreas
477 for j=1, #workAreas do
478 local workArea = workAreas[j]
479 if workArea.start ~= nil and workArea.width ~= nil then
480 local width = calcDistanceFrom(workArea.start, workArea.width)
481 maxWidth = math.max(maxWidth, width)
482
483 local x1, _, _ = localToLocal(workArea.start, sensorVehicle.rootNode, 0, 0, 0)
484 local x2, _, _ = localToLocal(workArea.width, sensorVehicle.rootNode, 0, 0, 0)
485 maxWidth = math.max(maxWidth, math.abs(x1) * 2, math.abs(x2) * 2)
486 end
487 end
488 end
489
490 if childVehicle.getAIMarkers ~= nil then
491 local leftMarker, rightMarker, _, _ = childVehicle:getAIMarkers()
492 if leftMarker ~= nil and rightMarker ~= nil then
493 local width = calcDistanceFrom(leftMarker, rightMarker)
494 maxWidth = math.max(maxWidth, width)
495
496 local x1, _, _ = localToLocal(leftMarker, sensorVehicle.rootNode, 0, 0, 0)
497 local x2, _, _ = localToLocal(rightMarker, sensorVehicle.rootNode, 0, 0, 0)
498 maxWidth = math.max(maxWidth, math.abs(x1) * 2, math.abs(x2) * 2)
499 end
500 end
501 end
502 end
503
504 return maxWidth
505end

getUseTurnedOnSchema

Description
Definition
getUseTurnedOnSchema()
Code
320function CropSensor:getUseTurnedOnSchema(superFunc)
321 return superFunc(self) or (self.spec_cropSensor ~= nil and self.spec_cropSensor.isStandaloneSensor and self.spec_cropSensor.isActive)
322end

initSpecialization

Description
Definition
initSpecialization()
Code
47function CropSensor.initSpecialization()
48 g_configurationManager:addConfigurationType("cropSensor", g_i18n:getText("configuration_cropSensor"), "cropSensor", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
49
50 local schema = Vehicle.xmlSchema
51 schema:setXMLSpecializationType("CropSensor")
52
53 schema:register(XMLValueType.NODE_INDEX, "vehicle.cropSensor.sensorNode(?)#node", "Sensor Node")
54 schema:register(XMLValueType.NODE_INDEX, "vehicle.cropSensor.sensorNode(?)#lightNode", "Real light source node")
55 schema:register(XMLValueType.NODE_INDEX, "vehicle.cropSensor.sensorNode(?)#staticLight", "Static light shape")
56 schema:register(XMLValueType.FLOAT, "vehicle.cropSensor.sensorNode(?)#radius", "Sensor radius", 18)
57 schema:register(XMLValueType.BOOL, "vehicle.cropSensor.sensorNode(?)#requiresDaylight", "Sensor requires daylight to work", false)
58 schema:register(XMLValueType.STRING, "vehicle.cropSensor.sensorNode(?)#pattern", "Sensor pattern (OCTAGON | ?)", "OCTAGON")
59
60 CropSensor.registerSensorLinkNodePaths(schema, "vehicle.cropSensor.cropSensorConfigurations.cropSensorConfiguration(?).sensorLinkNode(?)")
61
62 schema:setXMLSpecializationType()
63end

linkCropSensor

Description
Definition
linkCropSensor()
Code
409function CropSensor:linkCropSensor(linkData)
410 for i=1, #linkData.linkNodes do
411 local linkNodeData = linkData.linkNodes[i]
412
413 local linkNode = linkNodeData.node
414 if linkNode == nil and linkNodeData.nodeName ~= nil then
415 if self.i3dMappings[linkNodeData.nodeName] ~= nil then
416 linkNode = self.i3dMappings[linkNodeData.nodeName].nodeId
417 end
418 end
419
420 if linkNode ~= nil then
421 local sensorData = g_precisionFarming:getClonedCropSensorNode(linkNodeData.typeName)
422 if sensorData ~= nil then
423 link(linkNode, sensorData.node)
424
425 setTranslation(sensorData.node, linkNodeData.translation[1], linkNodeData.translation[2], linkNodeData.translation[3])
426 setRotation(sensorData.node, linkNodeData.rotation[1], linkNodeData.rotation[2], linkNodeData.rotation[3])
427
428 for j=1, #sensorData.rotationNodes do
429 local rotationNode = sensorData.rotationNodes[j]
430
431 local autoRotate = false
432 if linkNodeData.rotationNodes[j] ~= nil then
433 local vRotationNode = linkNodeData.rotationNodes[j]
434 if rotationNode.autoRotate and vRotationNode.autoRotate ~= false and vRotationNode.rotation == nil then
435 autoRotate = true
436 elseif vRotationNode.rotation ~= nil then
437 setRotation(rotationNode.node, vRotationNode.rotation[1], vRotationNode.rotation[2], vRotationNode.rotation[3])
438 end
439 else
440 autoRotate = rotationNode.autoRotate
441 end
442
443 if autoRotate then
444 local rx, ry, rz = localRotationToLocal(self:getParentComponent(sensorData.node), getParent(rotationNode.node), 0, 0, 0)
445 setRotation(rotationNode.node, rx, ry, rz)
446 end
447 end
448
449 if sensorData.measurementNode ~= nil then
450 local sensorNode = {}
451 sensorNode.node = sensorData.measurementNode
452 sensorNode.radius = 10
453 sensorNode.origRadius = sensorNode.radius
454 sensorNode.pattern = linkNodeData.typeName == "SENSOR_LEFT" and CropSensor.PATTERN_CORNER_LEFT or CropSensor.PATTERN_CORNER_RIGHT
455 sensorNode.requiresDaylight = sensorData.requiresDaylight
456 sensorNode.index = 1
457
458 table.insert(self.spec_cropSensor.sensorNodes, sensorNode)
459 end
460 end
461 end
462 end
463end

onDraw

Description
Definition
onDraw()
Code
220function CropSensor:onDraw()
221 if self.isClient then
222 if not self:getIsAIActive() then
223 local spec = self.spec_cropSensor
224 if spec.isAvailable and spec.isActive then
225 for i=1, #spec.sensorNodes do
226 local sensorNode = spec.sensorNodes[i]
227 if sensorNode.requiresDaylight then
228 if not g_currentMission.environment.isSunOn then
229 g_currentMission:showBlinkingWarning(spec.texts.warningSensorDaylight, 1000)
230 end
231 end
232 end
233 end
234 end
235 end
236end

onLoad

Description
Definition
onLoad()
Code
98function CropSensor:onLoad(savegame)
99 self.spec_cropSensor = self["spec_" .. CropSensor.SPEC_NAME]
100 local spec = self.spec_cropSensor
101
102 local baseName = "vehicle.cropSensor"
103
104 spec.sensorNodes = {}
105 self.xmlFile:iterate(baseName .. ".sensorNode", function(index, key)
106 local sensorNode = {}
107 sensorNode.node = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
108 if sensorNode.node ~= nil then
109 sensorNode.radius = self.xmlFile:getValue(key .. "#radius", 20)
110 sensorNode.origRadius = sensorNode.radius
111 sensorNode.requiresDaylight = self.xmlFile:getValue(key .. "#requiresDaylight", false)
112 local patternStr = self.xmlFile:getValue(key .. "#pattern", "OCTAGON")
113 local pattern = CropSensor["PATTERN_" .. patternStr:upper()]
114 if pattern == nil then
115 Logging.xmlWarning(self.xmlFile, "Wrong pattern '%s' ground in '%s'", patternStr, key)
116 end
117
118 sensorNode.lightNode = self.xmlFile:getValue(key .. "#lightNode", nil, self.components, self.i3dMappings)
119 if sensorNode.lightNode ~= nil then
120 setVisibility(sensorNode.lightNode, false)
121 end
122
123 sensorNode.staticLight = self.xmlFile:getValue(key .. "#staticLight", nil, self.components, self.i3dMappings)
124 if sensorNode.staticLight ~= nil then
125 setShaderParameter(sensorNode.staticLight, "lightControl", 0, 0, 0, 0, false)
126 end
127
128 sensorNode.pattern = pattern or CropSensor.PATTERN_OCTAGON
129 sensorNode.index = 1
130
131 table.insert(spec.sensorNodes, sensorNode)
132 end
133 end)
134
135 spec.isStandaloneSensor = #spec.sensorNodes > 0
136 spec.inputActionToggle = InputAction.PRECISIONFARMING_TOGGLE_CROP_SENSOR
137
138 local configIndex = self.configurations["cropSensor"]
139 if configIndex ~= nil then
140 local configKey = string.format("vehicle.cropSensor.cropSensorConfigurations.cropSensorConfiguration(%d)", configIndex - 1)
141
142 spec.sensorLinkNodeData = {}
143 spec.sensorLinkNodeData.linkNodes = {}
144 self.xmlFile:iterate(configKey .. ".sensorLinkNode", function(index, key)
145 local linkNode = {}
146 linkNode.node = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
147 if linkNode.node ~= nil then
148 linkNode.typeName = self.xmlFile:getValue(key .. "#type", "SENSOR_LEFT"):upper()
149 linkNode.translation = self.xmlFile:getValue(key .. "#translation", "0 0 0", true)
150 linkNode.rotation = self.xmlFile:getValue(key .. "#rotation", "0 0 0", true)
151
152 linkNode.rotationNodes = {}
153 self.xmlFile:iterate(key .. ".rotationNode", function(_, rotationNodeKey)
154 local rotatioNode = {}
155 rotatioNode.autoRotate = self.xmlFile:getValue(rotationNodeKey .. "#autoRotate")
156 rotatioNode.rotation = self.xmlFile:getValue(rotationNodeKey .. "#rotation", nil, true)
157
158 table.insert(linkNode.rotationNodes, rotatioNode)
159 end)
160
161 table.insert(spec.sensorLinkNodeData.linkNodes, linkNode)
162 end
163 end)
164
165 if #spec.sensorLinkNodeData.linkNodes > 0 then
166 self:linkCropSensor(spec.sensorLinkNodeData)
167 end
168
169 if configIndex > 1 then
170 if g_precisionFarming ~= nil then
171 local linkData = g_precisionFarming:getCropSensorLinkageData(self.configFileName)
172 if linkData ~= nil then
173 self:linkCropSensor(linkData)
174 end
175 end
176 end
177 end
178
179 spec.isAvailable = #spec.sensorNodes > 0
180 spec.isActive = false
181
182 spec.workingWidth = 0
183
184 if spec.isAvailable then
185 spec.texts = {}
186 spec.texts.toggleCropSensorPos = g_i18n:getText("action_toggleCropSensorPos", self.customEnvironment)
187 spec.texts.toggleCropSensorNeg = g_i18n:getText("action_toggleCropSensorNeg", self.customEnvironment)
188 spec.texts.warningSensorDaylight = g_i18n:getText("warning_sensorRequiresDaylight", self.customEnvironment)
189
190 if g_precisionFarming ~= nil then
191 spec.soilMap = g_precisionFarming.soilMap
192 spec.coverMap = g_precisionFarming.coverMap
193 spec.nitrogenMap = g_precisionFarming.nitrogenMap
194 spec.farmlandStatistics = g_precisionFarming.farmlandStatistics
195 end
196 end
197end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
240function CropSensor:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
241 if self.isClient then
242 local spec = self.spec_cropSensor
243 if spec.isAvailable then
244 self:clearActionEventsTable(spec.actionEvents)
245 if isActiveForInputIgnoreSelection then
246 local _, actionEventId = self:addActionEvent(spec.actionEvents, spec.inputActionToggle, self, CropSensor.actionEventToggle, false, true, false, true, nil)
247 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH)
248 CropSensor.updateActionEventTexts(self)
249 end
250 end
251 end
252end

onRootVehicleChanged

Description
Called if root vehicle changes
Definition
onRootVehicleChanged(table rootVehicle)
Arguments
tablerootVehicleroot vehicle
Code
257function CropSensor:onRootVehicleChanged(rootVehicle)
258 if self.isServer then
259 local spec = self.spec_cropSensor
260 if spec.isAvailable then
261 local actionController = rootVehicle.actionController
262 if actionController ~= nil then
263 if spec.controlledAction ~= nil then
264 spec.controlledAction:updateParent(actionController)
265 return
266 end
267
268 spec.controlledAction = actionController:registerAction("cropSensorTurnOn", nil, 1)
269 spec.controlledAction:setCallback(self, CropSensor.actionControllerToggleEvent)
270 spec.controlledAction:setFinishedFunctions(self, function() return spec.isActive end, true, false)
271 spec.controlledAction:setIsSaved(true)
272
273 spec.controlledAction:addAIEventListener(self, "onAIFieldWorkerStart", 1)
274 spec.controlledAction:addAIEventListener(self, "onAIFieldWorkerEnd", -1)
275
276 spec.controlledAction:addAIEventListener(self, "onAIImplementStart", 1)
277 spec.controlledAction:addAIEventListener(self, "onAIImplementEnd", -1)
278 else
279 if spec.controlledAction ~= nil then
280 spec.controlledAction:remove()
281 end
282 end
283 end
284 end
285end

onUpdate

Description
Called on update
Definition
onUpdate(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
204function CropSensor:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
205 if self.isServer then
206 local spec = self.spec_cropSensor
207 if spec.isAvailable and spec.isActive then
208 for i=1, #spec.sensorNodes do
209 local sensorNode = spec.sensorNodes[i]
210 if not sensorNode.requiresDaylight or g_currentMission.environment.isSunOn then
211 sensorNode.index = self:updateSensorNode(sensorNode.node, sensorNode.radius, sensorNode.pattern, sensorNode.index)
212 end
213 end
214 end
215 end
216end

prerequisitesPresent

Description
Checks if all prerequisite specializations are loaded
Definition
prerequisitesPresent(table specializations)
Arguments
tablespecializationsspecializations
Return Values
booleanhasPrerequisitetrue if all prerequisite specializations are loaded
Code
41function CropSensor.prerequisitesPresent(specializations)
42 return SpecializationUtil.hasSpecialization(PrecisionFarmingStatistic, specializations)
43end

setCropSensorActive

Description
Definition
setCropSensorActive()
Code
326function CropSensor:setCropSensorActive(state, noEventSend)
327 local spec = self.spec_cropSensor
328 if state == nil then
329 state = not spec.isActive
330 end
331
332 if state ~= spec.isActive then
333 if self.isClient then
334 for i=1, #spec.sensorNodes do
335 local sensorNode = spec.sensorNodes[i]
336 if sensorNode.lightNode ~= nil then
337 setVisibility(sensorNode.lightNode, state)
338 end
339 if sensorNode.staticLight ~= nil then
340 setShaderParameter(sensorNode.staticLight, "lightControl", state and 0.2 or 0, 0, 0, 0, false)
341 end
342 end
343 end
344
345 if state then
346 self:updateCropSensorWorkingWidth()
347 end
348
349 spec.isActive = state
350
351 CropSensor.updateActionEventTexts(self)
352 CropSensorStateEvent.sendEvent(self, state, noEventSend)
353 end
354end

updateActionEventTexts

Description
Definition
updateActionEventTexts()
Code
295function CropSensor.updateActionEventTexts(self)
296 local spec = self.spec_cropSensor
297 local actionEvent = spec.actionEvents[spec.inputActionToggle]
298 if actionEvent ~= nil then
299 g_inputBinding:setActionEventText(actionEvent.actionEventId, spec.isActive and spec.texts.toggleCropSensorNeg or spec.texts.toggleCropSensorPos)
300 end
301end

updateCropSensorWorkingWidth

Description
Definition
updateCropSensorWorkingWidth()
Code
359function CropSensor:updateCropSensorWorkingWidth()
360 local spec = self.spec_cropSensor
361 spec.workingWidth = CropSensor.getMaxWorkingWidth(self)
362
363 for i=1, #spec.sensorNodes do
364 local sensorNode = spec.sensorNodes[i]
365 self:updateSensorRadius(sensorNode, spec.workingWidth)
366 end
367end

updateSensorNode

Description
Definition
updateSensorNode()
Code
386function CropSensor:updateSensorNode(sensorNode, radius, pattern, index)
387 local spec = self.spec_cropSensor
388
389 if index > #pattern then
390 index = 1
391 end
392
393 for i=index, math.min(index+CropSensor.MAX_UPDATES_PER_FRAME-1, #pattern) do
394 local position = pattern[i]
395 local xs, _, zs = localToWorld(sensorNode, position[1] * radius, position[2] * radius, position[3] * radius)
396 local xw, _, zw = localToWorld(sensorNode, position[4] * radius, position[5] * radius, position[6] * radius)
397 local xh, _, zh = localToWorld(sensorNode, position[7] * radius, position[8] * radius, position[9] * radius)
398
399 spec.nitrogenMap:updateCropSensorArea(xs, zs, xw, zw, xh, zh)
400
401 index = i
402 end
403
404 return index + 1
405end

updateSensorRadius

Description
Definition
updateSensorRadius()
Code
371function CropSensor:updateSensorRadius(sensorNode, workingWidth)
372 if workingWidth > 0 then
373 local xOffset, _, _ = localToLocal(sensorNode.node, self.rootNode, 0, 0, 0)
374
375 -- 10% wider as the working width
376 workingWidth = workingWidth * 1.1
377
378 sensorNode.radius = math.max(workingWidth / 2 - math.abs(xOffset), CropSensor.MIN_SENSOR_RADIUS)
379 else
380 sensorNode.radius = sensorNode.origRadius
381 end
382end