LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

WorkParticles

Description
Specialization for adding various particles to vehicles while working
Functions

getDoGroundManipulation

Description
Definition
getDoGroundManipulation()
Code
212function WorkParticles:getDoGroundManipulation()
213 return true
214end

getFillTypeFromWorkAreaIndex

Description
Definition
getFillTypeFromWorkAreaIndex()
Code
423function WorkParticles:getFillTypeFromWorkAreaIndex(workAreaIndex)
424 local fillType = FillType.UNKNOWN
425 local workArea = self:getWorkAreaByIndex(workAreaIndex)
426 if workArea ~= nil then
427 if workArea.fillType ~= nil then
428 fillType = workArea.fillType
429 elseif workArea.fruitType ~= nil then
430 fillType = g_fruitTypeManager:getFruitTypeIndexByFillTypeIndex(workArea.fruitType)
431 end
432 end
433 return fillType
434end

loadGroundAnimationMapping

Description
Definition
loadGroundAnimationMapping()
Code
258function WorkParticles:loadGroundAnimationMapping(xmlFile, key, mapping, index)
259 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, key.."#index", key.."#node") --FS17 to FS19
260 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, key.."#animMeshIndex", key.."#animMeshNode") --FS17 to FS19
261
262 local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#node"), self.i3dMappings)
263 if node == nil then
264 g_logManager:xmlWarning(self.configFileName, "Invalid node '%s' for '%s'", getXMLString(xmlFile, key.."#node"), key)
265 return false
266 end
267
268 local groundRefIndex = getXMLInt(xmlFile, key .. "#refNodeIndex")
269 if groundRefIndex == nil or self:getGroundReferenceNodeFromIndex(groundRefIndex) == nil then
270 g_logManager:xmlWarning(self.configFileName, "Invalid refNodeIndex '%s' for '%s'", getXMLString(xmlFile, key.."#refNodeIndex"), key)
271 return false
272 end
273
274 local animNode
275 local animMeshNode = getXMLString(xmlFile, key.."#animMeshNode")
276 if animMeshNode ~= nil then
277 animNode = I3DUtil.indexToObject(node, animMeshNode, self.i3dMappings)
278 if animNode == nil then
279 g_logManager:xmlWarning(self.configFileName, "Invalid animMesh node '%s' '%s'", getXMLString(xmlFile, key.."#animMeshNode"), key)
280 return false
281 end
282 else
283 local materialType = getXMLString(xmlFile, key.."#materialType")
284 local materialId = Utils.getNoNil(getXMLInt(xmlFile, key.."#materialId"), 1)
285 if materialType == nil then
286 g_logManager:xmlWarning(self.configFileName, "Missing materialType in '%s'", key)
287 return false
288 end
289
290 animNode = node
291
292 local material = g_materialManager:getMaterial(FillType.UNKNOWN, materialType, materialId)
293 if material ~= nil then
294 setMaterial(node, material, 0)
295 else
296 g_logManager:xmlWarning(self.configFileName, "Invalid materialType '%s' or materialId '%s' in '%s'", materialType, materialId, key)
297 end
298
299 setVisibility(animNode, false)
300 end
301
302 mapping.node = node
303 mapping.animNode = animNode
304 mapping.groundRefNode = self:getGroundReferenceNodeFromIndex(groundRefIndex)
305 mapping.lastDepth = 0
306 mapping.speed = 0
307 mapping.maxWorkDepth = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxDepth"), -0.1)
308
309 return true
310end

loadGroundAnimations

Description
Definition
loadGroundAnimations()
Code
218function WorkParticles:loadGroundAnimations(xmlFile, key, animation, index)
219 local filenameStr = getXMLString(self.xmlFile, key .. "#file")
220 local i3dNode = nil
221 if filenameStr ~= nil then
222 i3dNode = g_i3DManager:loadSharedI3DFile(filenameStr, self.baseDirectory)
223 end
224
225 animation.speedThreshold = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#speedThreshold"), 0)
226
227 animation.mappings = {}
228 local j = 0
229 while true do
230 local nodeBaseName = string.format(key .. ".node(%d)", j)
231 if not hasXMLProperty(self.xmlFile, nodeBaseName) then
232 break
233 end
234
235 local mapping = {}
236 if self:loadGroundAnimationMapping(xmlFile, nodeBaseName, mapping, j, i3dNode) then
237 table.insert(animation.mappings, mapping)
238 end
239 j = j + 1
240 end
241
242 if i3dNode ~= nil and i3dNode ~= 0 then
243 -- link after loading to make sure all indices are correct
244 for _, mapping in ipairs(animation.mappings) do
245 link(mapping.node, mapping.animNode)
246 setVisibility(mapping.animNode, false)
247 end
248
249 animation.filename = filenameStr
250 delete(i3dNode)
251 end
252
253 return true
254end

loadGroundEffects

Description
Definition
loadGroundEffects()
Code
412function WorkParticles:loadGroundEffects(xmlFile, key, effect, index)
413 effect.speedThreshold = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#speedThreshold"), 0.5)
414 effect.workAreaIndex = getXMLInt(xmlFile, key .. "#workAreaIndex")
415 effect.needsSetIsTurnedOn = Utils.getNoNil(getXMLBool(xmlFile, key .. "#needsSetIsTurnedOn"), false)
416 effect.effect = g_effectManager:loadEffect(xmlFile, key, self.components, self, self.i3dMappings)
417
418 return true
419end

loadGroundParticleMapping

Description
Definition
loadGroundParticleMapping()
Code
355function WorkParticles:loadGroundParticleMapping(xmlFile, key, mapping, index, i3dNode)
356 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, key.."#index", key.."#node") --FS17 to FS19
357 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, key.."#particleIndex", key.."#particleNode") --FS17 to FS19
358
359 mapping.particleSystem = {}
360
361 local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#node"), self.i3dMappings)
362 if node == nil then
363 g_logManager:xmlWarning(self.configFileName, "Invalid node '%s' for '%s'", getXMLString(xmlFile, key.."#node"), key)
364 return false
365 end
366
367 local groundRefIndex = getXMLInt(xmlFile, key .. "#refNodeIndex")
368 if groundRefIndex == nil or self:getGroundReferenceNodeFromIndex(groundRefIndex) == nil then
369 g_logManager:xmlWarning(self.configFileName, "Invalid refNodeIndex '%s' for '%s'", getXMLString(xmlFile, key.."#refNodeIndex"), key)
370 return false
371 end
372
373 local particleNode
374 local particleNodeIndex = getXMLString(xmlFile, key.."#particleNode")
375 if particleNodeIndex ~= nil then
376 particleNode = I3DUtil.indexToObject(i3dNode, particleNodeIndex, self.i3dMappings)
377 if particleNode == nil then
378 g_logManager:xmlWarning(self.configFileName, "Invalid particle node '%s' '%s'", getXMLString(xmlFile, key.."#particleNode"), key)
379 return false
380 end
381 else
382 particleNode = node
383
384 local particleType = getXMLString(xmlFile, key.."#particleType")
385 if particleType == nil then
386 g_logManager:xmlWarning(self.configFileName, "Missing particleType in '%s'", key)
387 return false
388 end
389
390 local fillTypeStr = getXMLString(xmlFile, key.."#fillType")
391 local fillType = Utils.getNoNil(g_fillTypeManager:getFillTypeIndexByName(fillTypeStr), FillType.UNKNOWN)
392
393 local particleSystem = g_particleSystemManager:getParticleSystem(fillType, particleType)
394 if particleSystem ~= nil then
395 mapping.particleSystem = ParticleUtil.copyParticleSystem(xmlFile, key, particleSystem, node)
396 else
397 return false
398 end
399 end
400
401 mapping.node = node
402 mapping.particleNode = particleNode
403 mapping.groundRefNode = self:getGroundReferenceNodeFromIndex(groundRefIndex)
404 mapping.speedThreshold = Utils.getNoNil(getXMLFloat(xmlFile, key.."#speedThreshold"), 0.5)
405 mapping.movingDirection = getXMLInt(xmlFile, key.."#movingDirection")
406
407 return true
408end

loadGroundParticles

Description
Definition
loadGroundParticles()
Code
314function WorkParticles:loadGroundParticles(xmlFile, key, particle, index)
315 particle.mappings = {}
316
317 local filename = getXMLString(xmlFile, key .. "#file")
318 local i3dNode = nil
319 if filename ~= nil then
320 filename = Utils.getFilename(filename, self.baseDirectory)
321 i3dNode = loadI3DFile(filename, true, true, false)
322 end
323
324 local j = 0
325 while true do
326 local nodeBaseName = string.format(key .. ".node(%d)", j)
327 if not hasXMLProperty(xmlFile, nodeBaseName) then
328 break
329 end
330
331 local mapping = {}
332 if self:loadGroundParticleMapping(xmlFile, nodeBaseName, mapping, j, i3dNode) then
333 table.insert(particle.mappings, mapping)
334 end
335 j = j + 1
336 end
337
338
339 if i3dNode ~= nil and i3dNode ~= 0 then
340 -- link after loading to make sure all indices are correct
341 for _, mapping in ipairs(particle.mappings) do
342 link(mapping.node, mapping.particleNode)
343 ParticleUtil.loadParticleSystemFromNode(mapping.particleNode, mapping.particleSystem, false, true)
344 end
345
346 particle.filename = filename
347 delete(i3dNode)
348 end
349
350 return true
351end

loadGroundReferenceNode

Description
Definition
loadGroundReferenceNode()
Code
438function WorkParticles:loadGroundReferenceNode(superFunc, xmlFile, key, groundReferenceNode)
439 local returnValue = superFunc(self, xmlFile, key, groundReferenceNode)
440
441 if returnValue then
442 groundReferenceNode.depthNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#depthNode"), self.i3dMappings)
443 groundReferenceNode.movedDistance = 0
444 groundReferenceNode.depth = 0
445 groundReferenceNode.movingDirection = 0
446 end
447
448 return returnValue
449end

onDeactivate

Description
Definition
onDeactivate()
Code
477function WorkParticles:onDeactivate()
478 local spec = self.spec_workParticles
479
480 if self.isClient then
481 for _,ps in pairs(spec.particles) do
482 for _, mapping in ipairs(ps.mappings) do
483 ParticleUtil.setEmittingState(mapping.particleSystem, false)
484 end
485 end
486 for _, animation in ipairs(spec.particleAnimations) do
487 for _, mapping in ipairs(animation.mappings) do
488 setVisibility(mapping.animNode, false)
489 end
490 end
491 end
492end

onDelete

Description
Definition
onDelete()
Code
108function WorkParticles:onDelete()
109 local spec = self.spec_workParticles
110
111 if self.isClient then
112 for _, animation in ipairs(spec.particleAnimations) do
113 if animation.filename ~= nil then
114 g_i3DManager:releaseSharedI3DFile(animation.filename, self.baseDirectory, true)
115 end
116 end
117
118 for _, ps in pairs(spec.particles) do
119 for _, mapping in ipairs(ps.mappings) do
120 ParticleUtil.deleteParticleSystem(mapping.particleSystem)
121 end
122 end
123
124 for _, effect in pairs(spec.effects) do
125 g_effectManager:deleteEffects(effect.effect)
126 end
127 end
128end

onLoad

Description
Definition
onLoad()
Code
49function WorkParticles:onLoad(savegame)
50 local spec = self.spec_workParticles
51
52 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.groundParticleAnimations.groundParticleAnimation", "vehicle.workParticles.particleAnimation") --FS17 to FS19
53 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.groundParticleAnimations.groundParticle", "vehicle.workParticles.particle") --FS17 to FS19
54
55 if self.isClient then
56 spec.particleAnimations = {}
57 local i = 0
58 while true do
59 local key = string.format("vehicle.workParticles.particleAnimation(%d)", i)
60 if not hasXMLProperty(self.xmlFile, key) then
61 break
62 end
63
64 local animation = {}
65 if self:loadGroundAnimations(self.xmlFile, key, animation, i) then
66 table.insert(spec.particleAnimations, animation)
67 end
68
69 i = i + 1
70 end
71
72 spec.particles = {}
73 i = 0
74 while true do
75 local key = string.format("vehicle.workParticles.particle(%d)", i)
76 if not hasXMLProperty(self.xmlFile, key) then
77 break
78 end
79
80 local particle = {}
81 if self:loadGroundParticles(self.xmlFile, key, particle, i) then
82 table.insert(spec.particles, particle)
83 end
84
85 i = i + 1
86 end
87
88 spec.effects = {}
89 i = 0
90 while true do
91 local key = string.format("vehicle.workParticles.effect(%d)", i)
92 if not hasXMLProperty(self.xmlFile, key) then
93 break
94 end
95
96 local effect = {}
97 if self:loadGroundEffects(self.xmlFile, key, effect, i) then
98 table.insert(spec.effects, effect)
99 end
100
101 i = i + 1
102 end
103 end
104end

onUpdateTick

Description
Definition
onUpdateTick()
Code
133function WorkParticles:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
134 local spec = self.spec_workParticles
135
136 if self.isClient then
137 local isOnField = self:getIsOnField()
138
139 for _, animation in ipairs(spec.particleAnimations) do
140 for _, mapping in ipairs(animation.mappings) do
141 local refNode = mapping.groundRefNode
142 if refNode ~= nil and refNode.depthNode ~= nil then
143 local depth = MathUtil.clamp(refNode.depth / mapping.maxWorkDepth, 0, 1)
144 if not isOnField then
145 depth = 0
146 end
147
148 depth = MathUtil.clamp(math.min(depth, mapping.lastDepth + refNode.movingDirection * (refNode.movedDistance/0.5)), 0 ,1)
149 mapping.lastDepth = depth
150 mapping.speed = mapping.speed - (refNode.movedDistance * refNode.movingDirection)
151 setVisibility(mapping.animNode, depth > 0)
152 setShaderParameter(mapping.animNode, "VertxoffsetVertexdeformMotionUVscale", -6, depth, mapping.speed, 1.5, false)
153 end
154 end
155 end
156
157 local lastSpeed = self:getLastSpeed(true)
158 local enabled = self:getDoGroundManipulation() and isOnField
159
160 for _,ps in pairs(spec.particles) do
161 for _, mapping in ipairs(ps.mappings) do
162 local nodeEnabled = enabled
163 if nodeEnabled then
164 nodeEnabled = mapping.groundRefNode.isActive and lastSpeed > mapping.speedThreshold
165 end
166 if mapping.movingDirection ~= nil then
167 nodeEnabled = nodeEnabled and mapping.movingDirection == self.movingDirection
168 end
169 ParticleUtil.setEmittingState(mapping.particleSystem, nodeEnabled)
170 end
171 end
172
173 for _,effect in pairs(spec.effects) do
174 local state = enabled and lastSpeed > effect.speedThreshold
175
176 if effect.needsSetIsTurnedOn then
177 if self.getIsTurnedOn ~= nil then
178 local turnedOn = self:getIsTurnedOn()
179 if self.getAttacherVehicle ~= nil then
180 local attacherVehicle = self:getAttacherVehicle()
181 if attacherVehicle ~= nil then
182 if attacherVehicle.getIsTurnedOn ~= nil then
183 turnedOn = turnedOn or attacherVehicle:getIsTurnedOn()
184 end
185 end
186 end
187
188 state = state and turnedOn
189 end
190 end
191
192 local workArea = self:getWorkAreaByIndex(effect.workAreaIndex)
193 if workArea ~= nil then
194 if workArea.requiresGroundContact then
195 state = state and workArea.groundReferenceNode ~= nil and workArea.groundReferenceNode.isActive
196 end
197 end
198
199 if state then
200 local fillType = self:getFillTypeFromWorkAreaIndex(effect.workAreaIndex)
201 g_effectManager:setFillType(effect.effect, fillType)
202 g_effectManager:startEffects(effect.effect)
203 else
204 g_effectManager:stopEffects(effect.effect)
205 end
206 end
207 end
208end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
15function WorkParticles.prerequisitesPresent(specializations)
16 return true
17end

registerEventListeners

Description
Definition
registerEventListeners()
Code
40function WorkParticles.registerEventListeners(vehicleType)
41 SpecializationUtil.registerEventListener(vehicleType, "onLoad", WorkParticles)
42 SpecializationUtil.registerEventListener(vehicleType, "onDelete", WorkParticles)
43 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", WorkParticles)
44 SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", WorkParticles)
45end

registerFunctions

Description
Definition
registerFunctions()
Code
21function WorkParticles.registerFunctions(vehicleType)
22 SpecializationUtil.registerFunction(vehicleType, "getDoGroundManipulation", WorkParticles.getDoGroundManipulation)
23 SpecializationUtil.registerFunction(vehicleType, "loadGroundAnimations", WorkParticles.loadGroundAnimations)
24 SpecializationUtil.registerFunction(vehicleType, "loadGroundAnimationMapping", WorkParticles.loadGroundAnimationMapping)
25 SpecializationUtil.registerFunction(vehicleType, "loadGroundParticles", WorkParticles.loadGroundParticles)
26 SpecializationUtil.registerFunction(vehicleType, "loadGroundParticleMapping", WorkParticles.loadGroundParticleMapping)
27 SpecializationUtil.registerFunction(vehicleType, "loadGroundEffects", WorkParticles.loadGroundEffects)
28 SpecializationUtil.registerFunction(vehicleType, "getFillTypeFromWorkAreaIndex", WorkParticles.getFillTypeFromWorkAreaIndex)
29end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
33function WorkParticles.registerOverwrittenFunctions(vehicleType)
34 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadGroundReferenceNode", WorkParticles.loadGroundReferenceNode)
35 SpecializationUtil.registerOverwrittenFunction(vehicleType, "updateGroundReferenceNode", WorkParticles.updateGroundReferenceNode)
36end

updateGroundReferenceNode

Description
Definition
updateGroundReferenceNode()
Code
453function WorkParticles:updateGroundReferenceNode(superFunc, groundReferenceNode, x, y, z, terrainHeight, densityHeight)
454
455 superFunc(self, groundReferenceNode, x, y, z, terrainHeight, densityHeight)
456 if self.isClient and groundReferenceNode.depthNode ~= nil then
457 local newX, newY, newZ = getWorldTranslation(groundReferenceNode.depthNode)
458 if groundReferenceNode.lastPosition == nil then
459 groundReferenceNode.lastPosition = {newX, newY, newZ}
460 end
461 local dx, dy, dz = worldDirectionToLocal(groundReferenceNode.depthNode, newX-groundReferenceNode.lastPosition[1], newY-groundReferenceNode.lastPosition[2], newZ-groundReferenceNode.lastPosition[3])
462 groundReferenceNode.movingDirection = 0
463 if dz > 0.0001 then
464 groundReferenceNode.movingDirection = 1
465 elseif dz < -0.0001 then
466 groundReferenceNode.movingDirection = -1
467 end
468 groundReferenceNode.movedDistance = MathUtil.vector3Length(dx, dy, dz)
469 groundReferenceNode.lastPosition = {newX, newY, newZ}
470 local terrainHeightDepthNode = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, newX, newY, newZ)
471 groundReferenceNode.depth = newY - terrainHeightDepthNode
472 end
473end