LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

SpeedRotatingParts

Description
Specialization for vehicle with (non-wheel) parts rotating or scrolling dependent on its driving speed
Functions

getIsSpeedRotatingPartActive

Description
Returns true if speed rotating part is active
Definition
getIsSpeedRotatingPartActive(table speedRotatingPart)
Arguments
tablespeedRotatingPartspeedRotatingPart
Return Values
booleanisActivespeed rotating part is active
Code
259function SpeedRotatingParts:getIsSpeedRotatingPartActive(speedRotatingPart)
260 if speedRotatingPart.onlyActiveWhenLowered then
261 if self.getIsLowered ~= nil and not self:getIsLowered() then
262 return false
263 else
264 return true
265 end
266 end
267
268 return true
269end

getSpeedRotatingPartDirection

Description
Return direction of speed rotating part
Definition
getSpeedRotatingPartDirection(table speedRotatingPart)
Arguments
tablespeedRotatingPartspeed rotating part
Return Values
integerdirectiondirection
Code
275function SpeedRotatingParts:getSpeedRotatingPartDirection(speedRotatingPart)
276 return 1
277end

loadSpeedRotatingPartFromXML

Description
Loads speed rotating parts from xml
Definition
loadSpeedRotatingPartFromXML(table speedRotatingPart, integer xmlFile, string key)
Arguments
tablespeedRotatingPartspeedRotatingPart
integerxmlFileid of xml object
stringkeykey
Return Values
booleansuccesssuccess
Code
160function SpeedRotatingParts:loadSpeedRotatingPartFromXML(speedRotatingPart, xmlFile, key)
161 speedRotatingPart.repr = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#node"), self.i3dMappings)
162 speedRotatingPart.shaderNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#shaderNode"), self.i3dMappings)
163 if speedRotatingPart.shaderNode ~= nil then
164 speedRotatingPart.useShaderRotation = Utils.getNoNil(getXMLBool(xmlFile, key.."#useRotation"), true)
165 local scale = Utils.getNoNil(getXMLString(xmlFile, key.."#scrollScale"), "1 0")
166 speedRotatingPart.scrollScale = StringUtil.getVectorNFromString(scale, 2)
167 end
168
169 if speedRotatingPart.repr == nil and speedRotatingPart.shaderNode == nil then
170 g_logManager:xmlWarning(self.configFileName, "Invalid speedRotationPart node '%s' in '%s'", tostring(getXMLString(xmlFile, key.."#node")), key)
171 return false
172 end
173 speedRotatingPart.driveNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#driveNode"), self.i3dMappings), speedRotatingPart.repr)
174
175 local componentIndex = getXMLInt(xmlFile, key.."#refComponentIndex")
176 if componentIndex ~= nil and self.components[componentIndex] ~= nil then
177 speedRotatingPart.componentNode = self.components[componentIndex].node
178 else
179 local node = Utils.getNoNil(speedRotatingPart.driveNode, speedRotatingPart.shaderNode)
180 speedRotatingPart.componentNode = self:getParentComponent(node)
181 end
182
183 speedRotatingPart.xDrive = 0
184 local wheelIndex = getXMLInt(xmlFile, key.."#wheelIndex")
185 if wheelIndex ~= nil then
186 if self.getWheels == nil then
187 g_logManager:xmlWarning(self.configFileName, "wheelIndex for speedRotatingPart '%s' given, but no wheels loaded/defined", key)
188 else
189 local wheels = self:getWheels()
190 local wheel = wheels[wheelIndex]
191 if wheel == nil then
192 g_logManager:xmlWarning(self.configFileName, "Invalid wheel index '%s' for speedRotatingPart '%s'", tostring(wheelIndex), key)
193 return false
194 end
195 if not wheel.isSynchronized then
196 g_logManager:xmlDevWarning(self.configFileName, "referenced wheel with index '%s' for speedRotatingPart '%s' is not synchronized in multiplayer", tostring(wheelIndex), key)
197 end
198 speedRotatingPart.wheel = wheel
199 speedRotatingPart.lastWheelXRot = 0
200 end
201 end
202
203 speedRotatingPart.dirRefNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#dirRefNode"), self.i3dMappings)
204 speedRotatingPart.dirFrameNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#dirFrameNode"), self.i3dMappings)
205 speedRotatingPart.alignDirection = Utils.getNoNil(getXMLBool(xmlFile, key .. "#alignDirection"), false)
206 speedRotatingPart.applySteeringAngle = Utils.getNoNil(getXMLBool(xmlFile, key .. "#applySteeringAngle"), false)
207 speedRotatingPart.useWheelReprTranslation = Utils.getNoNil(getXMLBool(xmlFile, key .. "#useWheelReprTranslation"), true)
208 speedRotatingPart.updateXDrive = Utils.getNoNil(getXMLBool(xmlFile, key .. "#updateXDrive"), true)
209
210 speedRotatingPart.versatileYRot = Utils.getNoNil(getXMLBool(xmlFile, key .. "#versatileYRot"), false)
211 if speedRotatingPart.versatileYRot and speedRotatingPart.repr == nil then
212 g_logManager:xmlWarning(self.configFileName, "Versatile speedRotationPart '%s' does not support shaderNodes", key)
213 return false
214 end
215
216 local minYRot = getXMLFloat(xmlFile, key .. "#minYRot")
217 if minYRot ~= nil then
218 speedRotatingPart.minYRot = math.rad(minYRot)
219 end
220 local maxYRot = getXMLFloat(xmlFile, key .. "#maxYRot")
221 if maxYRot ~= nil then
222 speedRotatingPart.maxYRot = math.rad(maxYRot)
223 end
224 speedRotatingPart.steeringAngle = 0
225 speedRotatingPart.steeringAngleSent = 0
226
227 speedRotatingPart.wheelScale = getXMLFloat(xmlFile, key .. "#wheelScale")
228 if speedRotatingPart.wheelScale == nil then
229 local baseRadius = 1.0
230 local radius = 1.0
231 if speedRotatingPart.wheel ~= nil then
232 baseRadius = speedRotatingPart.wheel.radius
233 radius = speedRotatingPart.wheel.radius
234 end
235 speedRotatingPart.wheelScale = baseRadius / Utils.getNoNil(getXMLFloat(xmlFile, key.."#radius"), radius)
236 end
237
238 speedRotatingPart.wheelScaleBackup = speedRotatingPart.wheelScale
239
240 speedRotatingPart.onlyActiveWhenLowered = Utils.getNoNil(getXMLBool(xmlFile, key .. "#onlyActiveWhenLowered"), false)
241 speedRotatingPart.stopIfNotActive = Utils.getNoNil(getXMLBool(xmlFile, key .. "#stopIfNotActive"), false)
242 speedRotatingPart.fadeOutTime = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#fadeOutTime"), 3) * 1000
243 speedRotatingPart.activationSpeed = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#activationSpeed"), 1)
244 speedRotatingPart.speedReferenceNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#speedReferenceNode"), self.i3dMappings)
245 if speedRotatingPart.speedReferenceNode ~= nil and speedRotatingPart.speedReferenceNode == speedRotatingPart.driveNode then
246 g_logManager:xmlWarning(self.configFileName, "Ignoring speedRotationPart '%s' because speedReferenceNode is identical with driveNode. Need to be different!", key)
247 return false
248 end
249 speedRotatingPart.lastSpeed = 0
250 speedRotatingPart.lastDir = 1
251
252 return true
253end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
50function SpeedRotatingParts:onLoad(savegame)
51 local spec = self.spec_speedRotatingParts
52
53 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.speedRotatingParts.speedRotatingPart(0)#index", "vehicle.speedRotatingParts.speedRotatingPart(0)#node") -- FS17
54
55 spec.speedRotatingParts = {}
56 local i = 0
57 while true do
58 local baseName = string.format("vehicle.speedRotatingParts.speedRotatingPart(%d)", i)
59 if not hasXMLProperty(self.xmlFile, baseName) then
60 break
61 end
62 local speedRotatingPart = {}
63 if self:loadSpeedRotatingPartFromXML(speedRotatingPart, self.xmlFile, baseName) then
64 table.insert(spec.speedRotatingParts, speedRotatingPart)
65 end
66 i = i + 1
67 end
68
69 spec.dirtyFlag = self:getNextDirtyFlag()
70end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
76function SpeedRotatingParts:onReadStream(streamId, connection)
77 local spec = self.spec_speedRotatingParts
78 for _, speedRotatingPart in pairs(spec.speedRotatingParts) do
79 if speedRotatingPart.versatileYRot then
80 local yRot = streamReadUIntN(streamId, 9)
81 speedRotatingPart.steeringAngle = yRot / 511 * math.pi*2
82 end
83 end
84end

onReadUpdateStream

Description
Called on on update
Definition
onReadUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
104function SpeedRotatingParts:onReadUpdateStream(streamId, timestamp, connection)
105 if connection.isServer then
106 local spec = self.spec_speedRotatingParts
107 local hasUpdate = streamReadBool(streamId)
108 if hasUpdate then
109 for _, speedRotatingPart in pairs(spec.speedRotatingParts) do
110 if speedRotatingPart.versatileYRot then
111 local yRot = streamReadUIntN(streamId, 9)
112 speedRotatingPart.steeringAngle = yRot / 511 * math.pi*2
113 end
114 end
115 end
116 end
117end

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
143function SpeedRotatingParts:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
144 local spec = self.spec_speedRotatingParts
145
146 for _, speedRotatingPart in pairs(spec.speedRotatingParts) do
147 local isPartActive = self:getIsSpeedRotatingPartActive(speedRotatingPart)
148 if isPartActive or (speedRotatingPart.lastSpeed ~= 0 and not speedRotatingPart.stopIfNotActive) then
149 self:updateSpeedRotatingPart(speedRotatingPart, dt, isPartActive)
150 end
151 end
152end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
90function SpeedRotatingParts:onWriteStream(streamId, connection)
91 local spec = self.spec_speedRotatingParts
92 for _, speedRotatingPart in pairs(spec.speedRotatingParts) do
93 if speedRotatingPart.versatileYRot then
94 streamWriteUIntN(streamId, MathUtil.clamp(math.floor(speedRotatingPart.steeringAngle / (math.pi*2) * 511), 0, 511), 9)
95 end
96 end
97end

onWriteUpdateStream

Description
Called on on update
Definition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
124function SpeedRotatingParts:onWriteUpdateStream(streamId, connection, dirtyMask)
125 if not connection.isServer then
126 local spec = self.spec_speedRotatingParts
127 if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then
128 for _, speedRotatingPart in pairs(spec.speedRotatingParts) do
129 if speedRotatingPart.versatileYRot then
130 local yRot = speedRotatingPart.steeringAngle % (math.pi*2)
131 streamWriteUIntN(streamId, MathUtil.clamp(math.floor(yRot / (math.pi*2) * 511), 0, 511), 9)
132 end
133 end
134 end
135 end
136end

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
17function SpeedRotatingParts.prerequisitesPresent(specializations)
18 return true
19end

registerEventListeners

Description
Definition
registerEventListeners()
Code
38function SpeedRotatingParts.registerEventListeners(vehicleType)
39 SpecializationUtil.registerEventListener(vehicleType, "onLoad", SpeedRotatingParts)
40 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", SpeedRotatingParts)
41 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", SpeedRotatingParts)
42 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", SpeedRotatingParts)
43 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", SpeedRotatingParts)
44 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", SpeedRotatingParts)
45end

registerFunctions

Description
Definition
registerFunctions()
Code
23function SpeedRotatingParts.registerFunctions(vehicleType)
24 SpecializationUtil.registerFunction(vehicleType, "loadSpeedRotatingPartFromXML", SpeedRotatingParts.loadSpeedRotatingPartFromXML)
25 SpecializationUtil.registerFunction(vehicleType, "getIsSpeedRotatingPartActive", SpeedRotatingParts.getIsSpeedRotatingPartActive)
26 SpecializationUtil.registerFunction(vehicleType, "getSpeedRotatingPartDirection", SpeedRotatingParts.getSpeedRotatingPartDirection)
27 SpecializationUtil.registerFunction(vehicleType, "updateSpeedRotatingPart", SpeedRotatingParts.updateSpeedRotatingPart)
28end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
32function SpeedRotatingParts.registerOverwrittenFunctions(vehicleType)
33 SpecializationUtil.registerOverwrittenFunction(vehicleType, "validateWashableNode", SpeedRotatingParts.validateWashableNode)
34end

updateSpeedRotatingPart

Description
Definition
updateSpeedRotatingPart()
Code
281function SpeedRotatingParts:updateSpeedRotatingPart(speedRotatingPart, dt, isPartActive)
282 local spec = self.spec_speedRotatingParts
283 local speed = speedRotatingPart.lastSpeed
284 local dir = speedRotatingPart.lastDir
285
286 -- use angle from the repr node since the repr node could be rotated by another spec
287 if speedRotatingPart.repr ~= nil then
288 _, speedRotatingPart.steeringAngle, _ = getRotation(speedRotatingPart.repr)
289 end
290
291 if isPartActive then
292 if speedRotatingPart.wheel ~= nil then
293
294 local rotDiff = speedRotatingPart.wheel.netInfo.xDrive - speedRotatingPart.lastWheelXRot
295 if rotDiff > math.pi then
296 rotDiff = rotDiff - (2*math.pi)
297 elseif rotDiff < -math.pi then
298 rotDiff = rotDiff + (2*math.pi)
299 end
300 speed = math.abs(rotDiff)
301 dir = MathUtil.sign(rotDiff)
302 speedRotatingPart.lastWheelXRot = speedRotatingPart.wheel.netInfo.xDrive
303
304 _, speedRotatingPart.steeringAngle, _ = getRotation(speedRotatingPart.wheel.repr)
305
306 elseif speedRotatingPart.speedReferenceNode ~= nil then
307 local newX, newY, newZ = getWorldTranslation(speedRotatingPart.speedReferenceNode)
308 if speedRotatingPart.lastPosition == nil then
309 speedRotatingPart.lastPosition = {newX, newY, newZ}
310 end
311
312 local dx, dy, dz = worldDirectionToLocal(speedRotatingPart.speedReferenceNode, newX-speedRotatingPart.lastPosition[1], newY-speedRotatingPart.lastPosition[2], newZ-speedRotatingPart.lastPosition[3])
313 speed = MathUtil.vector3Length(dx, dy, dz)
314
315 if dz > 0.001 then
316 dir = 1
317 elseif dz < -0.001 then
318 dir = -1
319 else
320 dir = 0
321 end
322
323 speedRotatingPart.lastPosition[1], speedRotatingPart.lastPosition[2], speedRotatingPart.lastPosition[3] = newX, newY, newZ
324 else
325 speed = self.lastSpeedReal * dt
326 dir = self.movingDirection
327 end
328 speedRotatingPart.brakeForce = speed * dt/speedRotatingPart.fadeOutTime
329 else
330 speed = math.max(speed - speedRotatingPart.brakeForce, 0)
331 end
332
333 speedRotatingPart.lastSpeed = speed
334 speedRotatingPart.lastDir = dir
335 if speedRotatingPart.updateXDrive then
336 speedRotatingPart.xDrive = speedRotatingPart.xDrive + speed * dir * self:getSpeedRotatingPartDirection(speedRotatingPart) * speedRotatingPart.wheelScale
337 end
338
339 if speedRotatingPart.versatileYRot then
340 if speed > 0.0017 then -- 0.1deg threshold cause float accuracy
341 if self.isServer and self:getLastSpeed(true) > speedRotatingPart.activationSpeed then
342 local posX, posY, posZ = localToLocal(speedRotatingPart.repr, speedRotatingPart.componentNode, 0,0,0)
343 speedRotatingPart.steeringAngle = Utils.getVersatileRotation(speedRotatingPart.repr, speedRotatingPart.componentNode, dt, posX, posY, posZ, speedRotatingPart.steeringAngle, speedRotatingPart.minYRot, speedRotatingPart.maxYRot)
344 if math.abs(speedRotatingPart.steeringAngleSent-speedRotatingPart.steeringAngle) > 0.1 then
345 speedRotatingPart.steeringAngleSent = speedRotatingPart.steeringAngle
346 self:raiseDirtyFlags(spec.dirtyFlag)
347 end
348 end
349 end
350 else
351 if speedRotatingPart.componentNode ~= nil and speedRotatingPart.dirRefNode ~= nil and not speedRotatingPart.alignDirection then
352 speedRotatingPart.steeringAngle = Utils.getYRotationBetweenNodes(speedRotatingPart.componentNode, speedRotatingPart.dirRefNode)
353 local _,yTrans,_ = localToLocal(speedRotatingPart.driveNode, speedRotatingPart.wheel.driveNode, 0, 0, 0)
354 setTranslation(speedRotatingPart.driveNode, 0, yTrans, 0)
355 end
356
357 if speedRotatingPart.dirRefNode ~= nil and speedRotatingPart.alignDirection then
358 local upX, upY, upZ = localDirectionToWorld(speedRotatingPart.dirFrameNode, 0, 1, 0)
359 local dirX, dirY, dirZ = localDirectionToWorld(speedRotatingPart.dirRefNode, 0, 0, 1)
360 I3DUtil.setWorldDirection(speedRotatingPart.repr, dirX, dirY, dirZ, upX, upY, upZ, 2)
361 if speedRotatingPart.wheel ~= nil and speedRotatingPart.useWheelReprTranslation then
362 local _,yTrans,_ = localToLocal(speedRotatingPart.wheel.driveNode, getParent(speedRotatingPart.repr), 0,0,0)
363 setTranslation(speedRotatingPart.repr, 0, yTrans, 0)
364 end
365 end
366 end
367
368 if speedRotatingPart.driveNode ~= nil then
369 if speedRotatingPart.repr == speedRotatingPart.driveNode then
370 local steeringAngle =speedRotatingPart.steeringAngle
371 if not speedRotatingPart.applySteeringAngle then
372 steeringAngle = 0
373 end
374
375 setRotation(speedRotatingPart.repr, speedRotatingPart.xDrive, steeringAngle, 0)
376 else
377 if not speedRotatingPart.alignDirection and (speedRotatingPart.versatileYRot or speedRotatingPart.applySteeringAngle) then
378 setRotation(speedRotatingPart.repr, 0, speedRotatingPart.steeringAngle, 0)
379 end
380 setRotation(speedRotatingPart.driveNode, speedRotatingPart.xDrive, 0, 0)
381 end
382 end
383
384 if speedRotatingPart.shaderNode ~= nil then
385 if speedRotatingPart.useShaderRotation then
386 setShaderParameter(speedRotatingPart.shaderNode, "offsetUV", 0, 0, speedRotatingPart.xDrive, 0, false)
387 else
388 local pos = (speedRotatingPart.xDrive % math.pi) / (2*math.pi) -- normalize rotation
389 setShaderParameter(speedRotatingPart.shaderNode, "offsetUV", pos*speedRotatingPart.scrollScale[1], pos*speedRotatingPart.scrollScale[2], 0, 0, false)
390 end
391 end
392end

validateWashableNode

Description
Definition
validateWashableNode()
Code
396function SpeedRotatingParts:validateWashableNode(superFunc, node)
397 local spec = self.spec_speedRotatingParts
398 for _, speedRotatingPart in pairs(spec.speedRotatingParts) do
399 if speedRotatingPart.wheel ~= nil then
400 local speedRotatingPartsNodes = {}
401
402 if speedRotatingPart.repr ~= nil then
403 I3DUtil.getNodesByShaderParam(speedRotatingPart.repr, "RDT", speedRotatingPartsNodes)
404 end
405
406 if speedRotatingPart.shaderNode ~= nil then
407 I3DUtil.getNodesByShaderParam(speedRotatingPart.shaderNode, "RDT", speedRotatingPartsNodes)
408 end
409
410 if speedRotatingPart.driveNode ~= nil then
411 I3DUtil.getNodesByShaderParam(speedRotatingPart.driveNode, "RDT", speedRotatingPartsNodes)
412 end
413
414 if speedRotatingPartsNodes[node] ~= nil then
415 return false, self.updateWheelDirtAmount, speedRotatingPart.wheel, {wheel=speedRotatingPart.wheel, fieldDirtMultiplier=speedRotatingPart.wheel.fieldDirtMultiplier, streetDirtMultiplier=speedRotatingPart.wheel.streetDirtMultiplier, minDirtPercentage=speedRotatingPart.wheel.minDirtPercentage}
416 end
417 end
418 end
419
420 return superFunc(self, node)
421end