LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

CrabSteering

Description
Class for vehicles with variable steering modes (e.g. all wheel steering, crab steering, back wheel steering)
Functions

actionEventSetCrabSteeringMode

Description
Definition
actionEventSetCrabSteeringMode()
Code
533function CrabSteering.actionEventSetCrabSteeringMode(self, actionName, inputValue, callbackState, isAnalog)
534 local spec = self.spec_crabSteering
535 local state = spec.state
536
537 for i, mode in pairs(spec.steeringModes) do
538 if mode.inputAction == InputAction[actionName] then
539 state = i
540 break
541 end
542 end
543
544 if state ~= spec.state then
545 self:setCrabSteering(state)
546 end
547end

actionEventToggleCrabSteeringModes

Description
Definition
actionEventToggleCrabSteeringModes()
Code
519function CrabSteering.actionEventToggleCrabSteeringModes(self, actionName, inputValue, callbackState, isAnalog)
520 local spec = self.spec_crabSteering
521 local state = spec.state
522 state = state + 1
523 if state > spec.stateMax then
524 state = 1
525 end
526 if state ~= spec.state then
527 self:setCrabSteering(state)
528 end
529end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
479function CrabSteering:getCanBeSelected(superFunc)
480 return self.spec_crabSteering.stateMax > 0 or superFunc(self)
481end

onAIImplementStart

Description
Called on start ai vehicle
Definition
onAIImplementStart()
Code
485function CrabSteering:onAIImplementStart()
486 local spec = self.spec_crabSteering
487 if spec.stateMax > 0 then
488 self:setCrabSteering(spec.aiSteeringModeIndex, true)
489 end
490end

onDraw

Description
Called on draw
Definition
onDraw(boolean isActiveForInput, boolean isSelected)
Arguments
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
219function CrabSteering:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
220 local spec = self.spec_crabSteering
221 if spec.stateMax == 0 then
222 return
223 else
224 local mode = spec.steeringModes[spec.state]
225 g_currentMission:addExtraPrintText(string.format(g_i18n:getText("action_steeringModeSelected"), mode.name))
226 end
227end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
54function CrabSteering:onLoad(savegame)
55 local spec = self.spec_crabSteering
56
57 spec.state = 1
58 spec.stateMax = -1
59
60 spec.distFromCompJointToCenterOfBackWheels = getXMLFloat(self.xmlFile, "vehicle.crabSteering#distFromCompJointToCenterOfBackWheels")
61 spec.aiSteeringModeIndex = Utils.getNoNil(getXMLInt(self.xmlFile, "vehicle.crabSteering#aiSteeringModeIndex"), 1)
62 spec.toggleSpeedFactor = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.crabSteering#toggleSpeedFactor"), 1)
63
64 spec.currentArticulatedAxisOffset = 0
65 spec.articulatedAxisOffsetChanged = false
66 spec.articulatedAxisLastAngle = 0
67 spec.articulatedAxisChangingTime = 0
68
69 local baseKey = "vehicle.crabSteering"
70
71 spec.steeringModes = {}
72 local i = 0
73 while true do
74 local key = string.format("%s.steeringMode(%d)", baseKey, i)
75 if not hasXMLProperty(self.xmlFile, key) then
76 break
77 end
78
79 local entry = {}
80 entry.name = g_i18n:getText(getXMLString(self.xmlFile, key .. "#name"), self.customEnvironment)
81
82 local inputBindingName = getXMLString(self.xmlFile, key .. "#inputBindingName")
83 if inputBindingName ~= nil then
84 if InputAction[inputBindingName] ~= nil then
85 entry.inputAction = InputAction[inputBindingName]
86 else
87 g_logManager:xmlWarning(self.configFileName, "Invalid inputBindingname '%s' for '%s'", tostring(inputBindingName), key)
88 end
89 end
90
91 entry.wheels = {}
92 local j = 0
93 while true do
94 local wheelKey = string.format("%s.wheel(%d)", key, j)
95 if not hasXMLProperty(self.xmlFile, wheelKey) then
96 break
97 end
98 local wheelEntry = {}
99 wheelEntry.wheelIndex = getXMLInt(self.xmlFile, wheelKey .. "#index")
100 wheelEntry.offset = math.rad( Utils.getNoNil(getXMLFloat(self.xmlFile, wheelKey .. "#offset"), 0) )
101 wheelEntry.locked = Utils.getNoNil(getXMLBool(self.xmlFile, wheelKey .. "#locked"), false)
102
103 local wheels = self:getWheels()
104 if wheels[wheelEntry.wheelIndex] ~= nil then
105 wheels[wheelEntry.wheelIndex].steeringOffset = 0
106
107 wheels[wheelEntry.wheelIndex].rotSpeedBackUp = wheels[wheelEntry.wheelIndex].rotSpeed
108 else
109 g_logManager:xmlError(self.configFileName, "Invalid wheelIndex '%s' for '%s'", tostring(wheelEntry.wheelIndex), wheelKey)
110 end
111
112 table.insert(entry.wheels, wheelEntry)
113 j = j + 1
114 end
115
116 local specArticulatedAxis = self.spec_articulatedAxis
117 if specArticulatedAxis ~= nil and specArticulatedAxis.componentJoint ~= nil then
118 entry.articulatedAxis = {}
119 entry.articulatedAxis.rotSpeedBackUp = specArticulatedAxis.rotSpeed
120 entry.articulatedAxis.offset = math.rad( Utils.getNoNil(getXMLFloat(self.xmlFile, key .. ".articulatedAxis#offset"), 0) )
121 entry.articulatedAxis.locked = Utils.getNoNil(getXMLBool(self.xmlFile, key .. ".articulatedAxis#locked"), false)
122 entry.articulatedAxis.wheelIndices = {StringUtil.getVectorFromString(getXMLString(self.xmlFile, key .. ".articulatedAxis#wheelIndices"))}
123 end
124
125 entry.animations = {}
126 j = 0
127 while true do
128 local animKey = string.format("%s.animation(%d)", key, j)
129 if not hasXMLProperty(self.xmlFile, animKey) then
130 break
131 end
132 local animName = getXMLString(self.xmlFile, animKey .. "#name")
133 local animSpeed = Utils.getNoNil(getXMLFloat(self.xmlFile, animKey .. "#speed"), 1.0)
134 local stopTime = getXMLFloat(self.xmlFile, animKey .. "#stopTime")
135 if animName ~= nil and self:getAnimationExists(animName) then
136 table.insert(entry.animations, {animName=animName, animSpeed=animSpeed, stopTime=stopTime})
137 else
138 g_logManager:xmlWarning(self.configFileName, "Invalid animation '%s' for '%s'", tostring(animName), animKey)
139 end
140 j = j + 1
141 end
142
143 table.insert(spec.steeringModes, entry)
144 i = i + 1
145 end
146
147 spec.stateMax = table.getn(spec.steeringModes)
148 if spec.stateMax > ((2^CrabSteering.STEERING_SEND_NUM_BITS) - 1) then
149 g_logManager:xmlError(self.configFileName, "CrabSteering only supports %d steering modes!", (2^CrabSteering.STEERING_SEND_NUM_BITS) - 1)
150 end
151
152 if spec.stateMax > 0 then
153 self:setCrabSteering(1, true)
154 end
155end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
161function CrabSteering:onReadStream(streamId, connection)
162 local spec = self.spec_crabSteering
163 if spec.stateMax == 0 then
164 return
165 end
166 spec.state = streamReadUIntN(streamId, CrabSteering.STEERING_SEND_NUM_BITS)
167end

onReadUpdateStream

Description
Called on on update
Definition
onReadUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
186function CrabSteering:onReadUpdateStream(streamId, timestamp, connection)
187 local spec = self.spec_crabSteering
188 if spec.stateMax == 0 then
189 return
190 end
191
192 local specArticulatedAxis = self.spec_articulatedAxis
193 if specArticulatedAxis ~= nil and specArticulatedAxis.componentJoint ~= nil then
194 specArticulatedAxis.curRot = streamReadFloat32(streamId)
195 end
196end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
494function CrabSteering:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
495 if self.isClient then
496 local spec = self.spec_crabSteering
497 if spec.stateMax > 0 then
498
499 self:clearActionEventsTable(spec.actionEvents)
500
501 if isActiveForInputIgnoreSelection then
502 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_CRABSTEERING, self, CrabSteering.actionEventToggleCrabSteeringModes, false, true, false, true, nil)
503 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
504
505 for _, mode in pairs(spec.steeringModes) do
506 if mode.inputAction ~= nil then
507 _, actionEventId = self:addActionEvent(spec.actionEvents, mode.inputAction, self, CrabSteering.actionEventSetCrabSteeringMode, false, true, false, true, nil)
508 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
509 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
510 end
511 end
512 end
513 end
514 end
515end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
173function CrabSteering:onWriteStream(streamId, connection)
174 local spec = self.spec_crabSteering
175 if spec.stateMax == 0 then
176 return
177 end
178 streamWriteUIntN(streamId, spec.state, CrabSteering.STEERING_SEND_NUM_BITS)
179end

onWriteUpdateStream

Description
Called on on update
Definition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
203function CrabSteering:onWriteUpdateStream(streamId, connection, dirtyMask)
204 local spec = self.spec_crabSteering
205 if spec.stateMax == 0 then
206 return
207 end
208
209 local specArticulatedAxis = self.spec_articulatedAxis
210 if specArticulatedAxis ~= nil and specArticulatedAxis.componentJoint ~= nil then
211 streamWriteFloat32(streamId, specArticulatedAxis.curRot)
212 end
213end

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
18function CrabSteering.prerequisitesPresent(specializations)
19 return SpecializationUtil.hasSpecialization(Drivable, specializations)
20 and SpecializationUtil.hasSpecialization(Wheels, specializations)
21 and SpecializationUtil.hasSpecialization(AnimatedVehicle, specializations)
22end

registerEventListeners

Description
Definition
registerEventListeners()
Code
40function CrabSteering.registerEventListeners(vehicleType)
41 SpecializationUtil.registerEventListener(vehicleType, "onLoad", CrabSteering)
42 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", CrabSteering)
43 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", CrabSteering)
44 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", CrabSteering)
45 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", CrabSteering)
46 SpecializationUtil.registerEventListener(vehicleType, "onDraw", CrabSteering)
47 SpecializationUtil.registerEventListener(vehicleType, "onAIImplementStart", CrabSteering)
48 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", CrabSteering)
49end

registerFunctions

Description
Definition
registerFunctions()
Code
26function CrabSteering.registerFunctions(vehicleType)
27 SpecializationUtil.registerFunction(vehicleType, "setCrabSteering", CrabSteering.setCrabSteering)
28 SpecializationUtil.registerFunction(vehicleType, "updateSteeringAngle", CrabSteering.updateSteeringAngle)
29 SpecializationUtil.registerFunction(vehicleType, "updateArticulatedAxisRotation", CrabSteering.updateArticulatedAxisRotation)
30end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
34function CrabSteering.registerOverwrittenFunctions(vehicleType)
35 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", CrabSteering.getCanBeSelected)
36end

setCrabSteering

Description
Change crap steering mode
Definition
setCrabSteering(integer state, boolean noEventSend)
Arguments
integerstatenew state
booleannoEventSendno event send
Code
233function CrabSteering:setCrabSteering(state, noEventSend)
234 local spec = self.spec_crabSteering
235
236 if noEventSend == nil or noEventSend == false then
237 if g_server ~= nil then
238 g_server:broadcastEvent(SetCrabSteeringEvent:new(self, state), nil, nil, self)
239 else
240 g_client:getServerConnection():sendEvent(SetCrabSteeringEvent:new(self, state))
241 end
242 end
243
244 if state ~= spec.state then
245 local currentMode = spec.steeringModes[spec.state]
246 if currentMode.animations ~= nil then
247 for _,anim in pairs(currentMode.animations) do
248 local curTime = self:getAnimationTime(anim.animName)
249 if anim.stopTime == nil then
250 self:playAnimation(anim.animName, -anim.animSpeed, curTime, noEventSend)
251 end
252 end
253 end
254 local newMode = spec.steeringModes[state]
255 if newMode.animations ~= nil then
256 for _,anim in pairs(newMode.animations) do
257 local curTime = self:getAnimationTime(anim.animName)
258 if anim.stopTime ~= nil then
259 self:setAnimationStopTime(anim.animName, anim.stopTime)
260 local speed = 1.0
261 if curTime > anim.stopTime then
262 speed = -1.0
263 end
264 self:playAnimation(anim.animName, speed, curTime, noEventSend)
265 else
266 self:playAnimation(anim.animName, anim.animSpeed, curTime, noEventSend)
267 end
268 end
269 end
270 end
271
272 spec.state = state
273end

updateArticulatedAxisRotation

Description
Update articulated axis rotation
Definition
updateArticulatedAxisRotation(float steeringAngle, float dt)
Arguments
floatsteeringAnglesteering angle
floatdttime since last call in ms
Return Values
floatsteeringAngleadjusted steering angle
Code
364function CrabSteering:updateArticulatedAxisRotation(steeringAngle, dt)
365 local spec = self.spec_crabSteering
366 local specArticulatedAxis = self.spec_articulatedAxis
367 local specDriveable = self.spec_drivable
368
369 if spec.stateMax == 0 then
370 return steeringAngle
371 end
372
373 if not self.isServer then
374 return specArticulatedAxis.curRot
375 end
376
377 local currentMode = spec.steeringModes[spec.state]
378 if currentMode.articulatedAxis == nil then
379 return steeringAngle
380 end
381
382 --
383 local rotScale = math.min(1.0/(self.lastSpeed*specDriveable.speedRotScale+specDriveable.speedRotScaleOffset), 1)
384 local delta = dt*0.001*self.autoRotateBackSpeed*rotScale * spec.toggleSpeedFactor
385
386 if spec.currentArticulatedAxisOffset < currentMode.articulatedAxis.offset then
387 spec.currentArticulatedAxisOffset = math.min(currentMode.articulatedAxis.offset, spec.currentArticulatedAxisOffset + delta)
388 elseif spec.currentArticulatedAxisOffset > currentMode.articulatedAxis.offset then
389 spec.currentArticulatedAxisOffset = math.max(currentMode.articulatedAxis.offset, spec.currentArticulatedAxisOffset - delta)
390 end
391
392 -- adjust rotSpeed
393 if currentMode.articulatedAxis.locked then
394 if specArticulatedAxis.rotSpeed > 0 then
395 specArticulatedAxis.rotSpeed = math.max(0, specArticulatedAxis.rotSpeed - delta)
396 elseif specArticulatedAxis.rotSpeed < 0 then
397 specArticulatedAxis.rotSpeed = math.min(0, specArticulatedAxis.rotSpeed + delta)
398 end
399 else
400 if specArticulatedAxis.rotSpeed > currentMode.articulatedAxis.rotSpeedBackUp then
401 specArticulatedAxis.rotSpeed = math.max(currentMode.articulatedAxis.rotSpeedBackUp, specArticulatedAxis.rotSpeed - delta)
402 elseif specArticulatedAxis.rotSpeed < currentMode.articulatedAxis.rotSpeedBackUp then
403 specArticulatedAxis.rotSpeed = math.min(currentMode.articulatedAxis.rotSpeedBackUp, specArticulatedAxis.rotSpeed + delta)
404 end
405 end
406
407 local rotSpeed
408 if (self.rotatedTime) * (currentMode.articulatedAxis.rotSpeedBackUp) > 0 then
409 rotSpeed = (specArticulatedAxis.rotMax - spec.currentArticulatedAxisOffset) / self.wheelSteeringDuration
410 else
411 rotSpeed = (specArticulatedAxis.rotMin - spec.currentArticulatedAxisOffset) / self.wheelSteeringDuration
412 end
413
414 local f = math.abs(specArticulatedAxis.rotSpeed) / math.abs(currentMode.articulatedAxis.rotSpeedBackUp)
415 rotSpeed = rotSpeed * f
416
417 steeringAngle = spec.currentArticulatedAxisOffset + (math.abs(self.rotatedTime) * rotSpeed)
418
419 -- change rotation just if wheels are moving (so you don't have to steer in the opposite direction while turning on crab steering)
420 if table.getn(currentMode.articulatedAxis.wheelIndices) > 0 and spec.distFromCompJointToCenterOfBackWheels ~= nil and self.movingDirection >= 0 then
421 local wheels = self:getWheels()
422
423 local curRot = MathUtil.sign(currentMode.articulatedAxis.rotSpeedBackUp) * specArticulatedAxis.curRot
424
425 local alpha = 0
426 local count = 0
427 for _,wheelIndex in pairs(currentMode.articulatedAxis.wheelIndices) do
428 alpha = alpha + wheels[wheelIndex].steeringAngle
429 count = count + 1
430 end
431 alpha = alpha / count
432 alpha = alpha - curRot
433
434 local v = 0
435 count = 0
436 for _,wheelIndex in pairs(currentMode.articulatedAxis.wheelIndices) do
437 local wheel = wheels[wheelIndex]
438 local axleSpeed = getWheelShapeAxleSpeed(wheel.node, wheel.wheelShape) -- rad/sec
439 if wheel.hasGroundContact then
440 local longSlip, _ = getWheelShapeSlip(wheel.node, wheel.wheelShape)
441 local fac = 1.0 - math.min(1.0, longSlip)
442 v = v + fac * axleSpeed * wheel.radius
443 count = count + 1
444 end
445 end
446 v = v / count
447 local h = v * 0.001 * dt
448 local g = math.sin(alpha) * h
449 local a = math.cos(alpha) * h
450 local ls = spec.distFromCompJointToCenterOfBackWheels
451 local beta = math.atan2(g, ls - a)
452
453 steeringAngle = MathUtil.sign(currentMode.articulatedAxis.rotSpeedBackUp) * (curRot + beta)
454
455 spec.articulatedAxisOffsetChanged = true
456 spec.articulatedAxisLastAngle = steeringAngle
457 else
458 local changingTime = spec.articulatedAxisChangingTime
459 if spec.articulatedAxisOffsetChanged then
460 changingTime = 2500
461 spec.articulatedAxisOffsetChanged = false
462 end
463
464 --smooth blending if steering change is from crab to normal
465 if changingTime > 0 then
466 local pos = changingTime / 2500
467 steeringAngle = steeringAngle * (1-pos) + spec.articulatedAxisLastAngle * pos
468 spec.articulatedAxisChangingTime = changingTime - dt
469 end
470 end
471
472 steeringAngle = math.max(specArticulatedAxis.rotMin, math.min(specArticulatedAxis.rotMax, steeringAngle))
473
474 return steeringAngle
475end

updateSteeringAngle

Description
Update steering angle depending of the selected steering mode
Definition
updateSteeringAngle(table wheel, float dt, float steeringAngle)
Arguments
tablewheelwheel
floatdttime since last call in ms
floatsteeringAnglesteering angle
Return Values
floatsteeringAngleadjusted steering angle
Code
281function CrabSteering:updateSteeringAngle(wheel, dt, steeringAngle)
282 local spec = self.spec_crabSteering
283 local specWheels = self.spec_wheels
284 local specDriveable = self.spec_drivable
285
286 if spec.stateMax == 0 then
287 return steeringAngle
288 end
289
290 local currentMode = spec.steeringModes[spec.state]
291 if currentMode.wheels == nil or table.getn(currentMode.wheels) == 0 then
292 return steeringAngle
293 end
294
295 for _, wheelProperties in pairs(currentMode.wheels) do
296 if specWheels.wheels[wheelProperties.wheelIndex] == wheel then
297 local rotScale = math.min(1.0/(self.lastSpeed*specDriveable.speedRotScale+specDriveable.speedRotScaleOffset), 1)
298 local delta = dt*0.001*self.autoRotateBackSpeed*rotScale * spec.toggleSpeedFactor
299
300 if wheel.steeringOffset < wheelProperties.offset then
301 wheel.steeringOffset = math.min(wheelProperties.offset, wheel.steeringOffset + delta)
302 elseif wheel.steeringOffset > wheelProperties.offset then
303 wheel.steeringOffset = math.max(wheelProperties.offset, wheel.steeringOffset - delta)
304 end
305
306 if not wheelProperties.locked then
307
308 local rotSpeed
309 if self.rotatedTime > 0 then
310 rotSpeed = (wheel.rotMax - wheel.steeringOffset) / self.wheelSteeringDuration
311 if wheel.rotSpeedBackUp < 0 then
312 rotSpeed = (wheel.rotMin - wheel.steeringOffset) / self.wheelSteeringDuration
313 end
314 else
315 rotSpeed = -(wheel.rotMin - wheel.steeringOffset) / self.wheelSteeringDuration
316 if wheel.rotSpeedBackUp < 0 then
317 rotSpeed = -(wheel.rotMax - wheel.steeringOffset) / self.wheelSteeringDuration
318 end
319 end
320
321 if wheel.rotSpeed < wheel.rotSpeedBackUp then
322 wheel.rotSpeed = math.min(wheel.rotSpeedBackUp, wheel.rotSpeed + delta)
323 elseif wheel.rotSpeed > wheel.rotSpeedBackUp then
324 wheel.rotSpeed = math.max(wheel.rotSpeedBackUp, wheel.rotSpeed - delta)
325 end
326 local f = wheel.rotSpeed / wheel.rotSpeedBackUp
327
328 steeringAngle = wheel.steeringOffset + (self.rotatedTime * f * rotSpeed)
329
330 else
331
332 if wheel.steeringAngle > wheel.steeringOffset or steeringAngle > wheel.steeringOffset then
333 steeringAngle = math.max(wheel.steeringOffset, math.min(wheel.steeringAngle, steeringAngle) - delta)
334 elseif wheel.steeringAngle < wheel.steeringOffset or steeringAngle < wheel.steeringOffset then
335 steeringAngle = math.min(wheel.steeringOffset, math.max(wheel.steeringAngle, steeringAngle) + delta)
336 end
337
338 if steeringAngle == wheel.steeringOffset then
339 wheel.rotSpeed = 0
340 else
341 if wheel.rotSpeed < 0 then
342 wheel.rotSpeed = math.min(0, wheel.rotSpeed + delta)
343 elseif wheel.rotSpeed > 0 then
344 wheel.rotSpeed = math.max(0, wheel.rotSpeed - delta)
345 end
346 end
347
348 end
349
350 steeringAngle = MathUtil.clamp(steeringAngle, wheel.rotMin, wheel.rotMax)
351
352 break
353 end
354 end
355
356 return steeringAngle
357end