LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

ArticulatedAxis

Description
Specialization for vehicles which steer with an articulated axis (excavators, loaders ...)
Functions

getSteeringRotTimeByCurvature

Description
Definition
getSteeringRotTimeByCurvature()
Code
318function ArticulatedAxis:getSteeringRotTimeByCurvature(superFunc, curvature)
319 return self.wheelSteeringDuration * ( math.atan(curvature) / math.atan(1/self.maxTurningRadius))
320end

getTurningRadiusByRotTime

Description
Definition
getTurningRadiusByRotTime()
Code
324function ArticulatedAxis:getTurningRadiusByRotTime(superFunc, rotTime)
325 local spec = self.spec_articulatedAxis
326 if spec.componentJoint == nil then
327 return superFunc(self, rotTime)
328 end
329
330 local rotSpeed = spec.rotSpeed
331 local rotMax = self.maxRotation
332
333 local curvature = -math.tan((rotTime / (MathUtil.sign(rotSpeed) * rotMax / rotSpeed)) * math.atan(1/self.maxTurningRadius))
334
335 if curvature == 0 then
336 return math.huge
337 end
338
339 return 1 / curvature
340end

initSpecialization

Description
Definition
initSpecialization()
Code
23function ArticulatedAxis.initSpecialization()
24 local schema = Vehicle.xmlSchema
25 schema:setXMLSpecializationType("ArticulatedAxis")
26
27 schema:register(XMLValueType.INT, "vehicle.articulatedAxis#componentJointIndex", "Index of component joint")
28 schema:register(XMLValueType.ANGLE, "vehicle.articulatedAxis#rotSpeed", "Rotation speed")
29 schema:register(XMLValueType.ANGLE, "vehicle.articulatedAxis#rotMax", "Max rotation")
30 schema:register(XMLValueType.ANGLE, "vehicle.articulatedAxis#rotMin", "Min rotation")
31 schema:register(XMLValueType.INT, "vehicle.articulatedAxis#anchorActor", "Anchor actor index", 0)
32 schema:register(XMLValueType.NODE_INDEX, "vehicle.articulatedAxis#rotNode", "Rotation node")
33 schema:register(XMLValueType.NODE_INDEX, "vehicle.articulatedAxis#aiRevereserNode", "AI reverser node")
34 schema:register(XMLValueType.FLOAT, "vehicle.articulatedAxis#maxTurningRadius", "Fixed turning radius to overwrite automatic calculations")
35 schema:register(XMLValueType.VECTOR_N, "vehicle.articulatedAxis#customWheelIndices1", "Component 1 wheel indices. Needed if wheels are not linked to component 1 directly. E.g. dolly axis")
36 schema:register(XMLValueType.VECTOR_N, "vehicle.articulatedAxis#customWheelIndices2", "Component 2 wheel indices. Needed if wheels are not linked to component 2 directly. E.g. dolly axis")
37
38 schema:register(XMLValueType.NODE_INDEX, "vehicle.articulatedAxis.rotatingPart(?)#node", "Rotation part node")
39 schema:register(XMLValueType.VECTOR_ROT, "vehicle.articulatedAxis.rotatingPart(?)#posRot", "Positive rotation")
40 schema:register(XMLValueType.VECTOR_ROT, "vehicle.articulatedAxis.rotatingPart(?)#negRot", "Negative rotation")
41 schema:register(XMLValueType.FLOAT, "vehicle.articulatedAxis.rotatingPart(?)#posRotFactor", "Positive rotation factor", 1)
42 schema:register(XMLValueType.FLOAT, "vehicle.articulatedAxis.rotatingPart(?)#negRotFactor", "Negative rotation factor", 1)
43 schema:register(XMLValueType.BOOL, "vehicle.articulatedAxis.rotatingPart(?)#invertSteeringAngle", "Invert steering angle", false)
44
45 SoundManager.registerSampleXMLPaths(schema, "vehicle.articulatedAxis.sounds", "steering")
46
47 schema:setXMLSpecializationType()
48end

onDeactivate

Description
Definition
onDeactivate()
Code
245function ArticulatedAxis:onDeactivate()
246 if self.isClient then
247 local spec = self.spec_articulatedAxis
248 g_soundManager:stopSamples(spec.samples)
249 spec.isSteeringSoundPlaying = false
250 end
251end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
236function ArticulatedAxis:onDelete()
237 if self.isClient then
238 local spec = self.spec_articulatedAxis
239 g_soundManager:deleteSamples(spec.samples)
240 end
241end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
70function ArticulatedAxis:onLoad(savegame)
71 local xmlFile = self.xmlFile
72 local spec = self.spec_articulatedAxis
73
74 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.articulatedAxis.rotatingPart(0)#index", "vehicle.articulatedAxis.rotatingPart(0)#node") -- FS17
75
76 local index = xmlFile:getValue("vehicle.articulatedAxis#componentJointIndex")
77 if index ~= nil then
78 if index == 0 then
79 Logging.xmlWarning(self.xmlFile, "Invalid component joint index '0' for articulatedAxis. Indices start with 1!")
80 else
81 local componentJoint = self.componentJoints[index]
82 local rotSpeed = xmlFile:getValue("vehicle.articulatedAxis#rotSpeed")
83 local rotMax = xmlFile:getValue("vehicle.articulatedAxis#rotMax")
84 local rotMin = xmlFile:getValue("vehicle.articulatedAxis#rotMin")
85 if componentJoint ~= nil and rotSpeed ~= nil and rotMax ~= nil and rotMin ~= nil then
86 spec.rotSpeed = rotSpeed
87 spec.rotMax = rotMax
88 spec.rotMin = rotMin
89
90 spec.componentJoint = componentJoint
91 spec.anchorActor = xmlFile:getValue( "vehicle.articulatedAxis#anchorActor", 0)
92 spec.rotationNode = xmlFile:getValue("vehicle.articulatedAxis#rotNode", nil, self.components, self.i3dMappings)
93 if spec.rotationNode == nil then
94 spec.rotationNode = spec.componentJoint.jointNode
95 end
96
97 spec.curRot = 0
98
99 local i = 0
100 spec.rotatingParts = {}
101 while true do
102 local key = string.format("vehicle.articulatedAxis.rotatingPart(%d)", i)
103 if not xmlFile:hasProperty(key) then
104 break
105 end
106
107 local node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
108 if node ~= nil then
109 local rotatingPart = {}
110 rotatingPart.node = node
111 rotatingPart.defRot = {getRotation(node)}
112 rotatingPart.posRot = xmlFile:getValue(key .. "#posRot", nil, true)
113 rotatingPart.negRot = xmlFile:getValue(key .. "#negRot", nil, true)
114 rotatingPart.negRotFactor = xmlFile:getValue(key .. "#negRotFactor", 1)
115 rotatingPart.posRotFactor = xmlFile:getValue(key .. "#posRotFactor", 1)
116 rotatingPart.invertSteeringAngle = xmlFile:getValue(key .. "#invertSteeringAngle", false)
117 table.insert(spec.rotatingParts, rotatingPart)
118 else
119 Logging.xmlWarning(self.xmlFile, "Failed to load rotation part '%s'", key)
120 end
121 i = i + 1
122 end
123
124 local customWheelIndices = {{}, {}}
125 local customWheelIndices1Sorted = xmlFile:getValue("vehicle.articulatedAxis#customWheelIndices1", nil, true)
126 if customWheelIndices1Sorted ~= nil then
127 for _, wheelIndex in ipairs(customWheelIndices1Sorted) do
128 customWheelIndices[1][wheelIndex] = true
129 end
130 end
131 local customWheelIndices2Sorted = xmlFile:getValue("vehicle.articulatedAxis#customWheelIndices2", nil, true)
132 if customWheelIndices2Sorted ~= nil then
133 for _, wheelIndex in ipairs(customWheelIndices2Sorted) do
134 customWheelIndices[2][wheelIndex] = true
135 end
136 end
137
138 -- adjust steering values
139 local maxRotTime = rotMax/rotSpeed
140 local minRotTime = rotMin/rotSpeed
141 if minRotTime > maxRotTime then
142 local temp = minRotTime
143 minRotTime = maxRotTime
144 maxRotTime = temp
145 end
146 if maxRotTime > self.maxRotTime then
147 self.maxRotTime = maxRotTime
148 end
149 if minRotTime < self.minRotTime then
150 self.minRotTime = minRotTime
151 end
152
153 self.maxRotation = rotMax
154 self.wheelSteeringDuration = MathUtil.sign(rotSpeed) * rotMax / rotSpeed
155
156 -- adjust variables used by AIVehicleUtil
157 spec.aiRevereserNode = xmlFile:getValue("vehicle.articulatedAxis#aiRevereserNode", nil, self.components, self.i3dMappings)
158
159 local maxTurningRadius = 0
160 local specWheels = self.spec_wheels
161 for j=1,2 do
162 local rootNode = self.components[componentJoint.componentIndices[j]].node
163
164 for wheelIndex, wheel in ipairs(specWheels.wheels) do
165 if self:getParentComponent(wheel.repr) == rootNode or customWheelIndices[j][wheelIndex] ~= nil then
166
167 local wx,_,wz = localToLocal(wheel.driveNode, rootNode, 0,0,0)
168 local dx1 = 1
169 if wx < 0 then
170 dx1 = -1
171 end
172 local dz1 = math.tan( math.max(wheel.rotMin, wheel.rotMax) )
173 if wz > 0 then
174 dz1 = -dz1
175 end
176
177 local x2, z2 = 0, 0
178 local dx2 = 1
179 if wx < 0 then
180 dx2 = -1
181 end
182 local dz2 = math.tan( math.max(rotMin, rotMax) )
183 if wz < 0 then
184 dz2 = -dz2
185 end
186
187 -- normalize directions
188 local l1 = MathUtil.vector2Length(dx1, dz1)
189 dx1, dz1 = dx1 / l1, dz1 / l1
190
191 local l2 = MathUtil.vector2Length(dx2, dz2)
192 dx2, dz2 = dx2 / l2, dz2 / l2
193
194 local intersect, _, f2 = MathUtil.getLineLineIntersection2D(wx,wz, dx1,dz1, x2,z2, dx2,dz2)
195 if intersect then
196 local radius = math.abs(f2)
197 maxTurningRadius = math.max(maxTurningRadius, radius)
198 end
199 end
200 end
201 end
202
203 if maxTurningRadius ~= 0 then
204 self.maxTurningRadius = maxTurningRadius
205 end
206
207 self.maxTurningRadius = xmlFile:getValue("vehicle.articulatedAxis#maxTurningRadius", self.maxTurningRadius)
208 end
209 end
210 end
211
212 if self.isClient then
213 spec.samples = {}
214 spec.samples.steering = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.articulatedAxis.sounds", "steering", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
215 spec.isSteeringSoundPlaying = false
216 end
217
218 spec.interpolatedRotatedTime = 0
219end

onPostLoad

Description
Definition
onPostLoad()
Code
223function ArticulatedAxis:onPostLoad()
224 local spec = self.spec_articulatedAxis
225 if spec.componentJoint ~= nil then
226 if self.updateArticulatedAxisRotation ~= nil then
227 self:updateArticulatedAxisRotation(0, 99999)
228 end
229 else
230 SpecializationUtil.removeEventListener(self, "onUpdate", ArticulatedAxis)
231 end
232end

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
258function ArticulatedAxis:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
259 local spec = self.spec_articulatedAxis
260 -- interpolatedRotatedTime to manipulate camera rot
261 if spec.interpolatedRotatedTime < self.rotatedTime then
262 spec.interpolatedRotatedTime = math.min(self.rotatedTime, spec.interpolatedRotatedTime + math.abs(spec.rotSpeed) * dt/500)
263 elseif spec.interpolatedRotatedTime > self.rotatedTime then
264 spec.interpolatedRotatedTime = math.max(self.rotatedTime, spec.interpolatedRotatedTime - math.abs(spec.rotSpeed) * dt/500)
265 end
266
267 local steeringAngle = MathUtil.clamp(self.rotatedTime * spec.rotSpeed, spec.rotMin, spec.rotMax)
268 if self.updateArticulatedAxisRotation ~= nil then
269 steeringAngle = self:updateArticulatedAxisRotation(steeringAngle, dt)
270 end
271
272 if self.isClient then
273 local isSteering = math.abs(steeringAngle - spec.curRot) > 0.0001
274 if isSteering ~= spec.isSteeringSoundPlaying then
275 if isSteering then
276 g_soundManager:playSample(spec.samples.steering)
277 else
278 g_soundManager:stopSample(spec.samples.steering)
279 end
280
281 spec.isSteeringSoundPlaying = isSteering
282 end
283 end
284
285 if math.abs(steeringAngle - spec.curRot) > 0.000001 then
286 if self.isServer then
287 setRotation(spec.rotationNode, 0, steeringAngle, 0)
288 self:setComponentJointFrame(spec.componentJoint, spec.anchorActor)
289 spec.curRot = steeringAngle
290 end
291
292 if self.isClient then
293 local percent = 0
294 if steeringAngle > 0 then
295 percent = steeringAngle / spec.rotMax
296 elseif steeringAngle < 0 then
297 percent = steeringAngle / spec.rotMin
298 end
299
300 for _,rotPart in pairs(spec.rotatingParts) do
301 local rx,ry,rz
302 if (steeringAngle > 0 and not rotPart.invertSteeringAngle) or (steeringAngle < 0 and rotPart.invertSteeringAngle) then
303 rx,ry,rz = MathUtil.vector3ArrayLerp(rotPart.defRot, rotPart.posRot, math.min(1,percent*rotPart.posRotFactor))
304 else
305 rx,ry,rz = MathUtil.vector3ArrayLerp(rotPart.defRot, rotPart.negRot, math.min(1,percent*rotPart.negRotFactor))
306 end
307 setRotation(rotPart.node, rx,ry,rz)
308 if self.setMovingToolDirty ~= nil then
309 self:setMovingToolDirty(rotPart.node)
310 end
311 end
312 end
313 end
314end

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 ArticulatedAxis.prerequisitesPresent(specializations)
18 return SpecializationUtil.hasSpecialization(Drivable, specializations)
19end

registerEventListeners

Description
Definition
registerEventListeners()
Code
59function ArticulatedAxis.registerEventListeners(vehicleType)
60 SpecializationUtil.registerEventListener(vehicleType, "onLoad", ArticulatedAxis)
61 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", ArticulatedAxis)
62 SpecializationUtil.registerEventListener(vehicleType, "onDelete", ArticulatedAxis)
63 SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", ArticulatedAxis)
64 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", ArticulatedAxis)
65end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
52function ArticulatedAxis.registerOverwrittenFunctions(vehicleType)
53 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getSteeringRotTimeByCurvature", ArticulatedAxis.getSteeringRotTimeByCurvature)
54 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getTurningRadiusByRotTime", ArticulatedAxis.getTurningRadiusByRotTime)
55end