LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

AIDrivable

Description
Specialization for extending vehicles to by used by AI helpers
Functions

addAIAgentAttachment

Description
Definition
addAIAgentAttachment()
Code
643function AIDrivable:addAIAgentAttachment(attachmentData, level)
644 local spec = self.spec_aiDrivable
645
646 spec.attachmentsMaxWidth = math.max(spec.attachmentsMaxWidth, attachmentData.width)
647 spec.attachmentsMaxHeight = math.max(spec.attachmentsMaxHeight, attachmentData.height)
648
649 attachmentData.level = level
650
651 if spec.attachmentChains[spec.attachmentChainIndex] == nil then
652 spec.attachmentChains[spec.attachmentChainIndex] = {}
653 end
654
655 table.insert(spec.attachments, attachmentData)
656 table.insert(spec.attachmentChains[spec.attachmentChainIndex], attachmentData)
657end

consoleCommandMove

Description
Definition
consoleCommandMove()
Code
826function AIDrivable:consoleCommandMove(distance)
827 local vehicles = {}
828 local attachedVehicles = self:getChildVehicles()
829 for _, vehicle in ipairs(attachedVehicles) do
830 vehicle:removeFromPhysics()
831 table.insert(vehicles, vehicle)
832 end
833
834 local aiRootNode = self:getAIRootNode()
835 local dirX, dirY, dirZ = localDirectionToWorld(aiRootNode, 1, 0, 0)
836 local moveX, moveY, moveZ = dirX*distance, dirY*distance, dirZ*distance
837 local currentTurnRadius = self:getTurningRadiusByRotTime(self.rotatedTime)
838
839 local gizmo = DebugGizmo.new()
840 local x, y, z = localToWorld(aiRootNode, currentTurnRadius, 0.05, 0)
841 gizmo:createWithWorldPosAndDir(x, y, z, 0, 0, 1, 0, 1, 0, "", false, nil)
842 g_debugManager:addPermanentElement(gizmo)
843
844 currentTurnRadius = -currentTurnRadius + distance
845 self.rotatedTime = self:getSteeringRotTimeByCurvature(1 / currentTurnRadius)
846
847 if self.rotatedTime < 0 then
848 self.spec_wheels.axisSide = self.rotatedTime / -self.maxRotTime / self:getSteeringDirection()
849 else
850 self.spec_wheels.axisSide = self.rotatedTime / self.minRotTime / self:getSteeringDirection()
851 end
852
853 for _, vehicle in ipairs(vehicles) do
854 for _, component in ipairs(vehicle.components) do
855 x, y, z = getWorldTranslation(component.node)
856 setWorldTranslation(component.node, x + moveX, y + moveY, z + moveZ)
857 end
858 end
859
860 for _, vehicle in ipairs(vehicles) do
861 vehicle:addToPhysics()
862 end
863end

consoleCommandSetTurnRadius

Description
Definition
consoleCommandSetTurnRadius()
Code
807function AIDrivable:consoleCommandSetTurnRadius(turnRadius)
808 turnRadius = tonumber(turnRadius) or 10
809
810 local rotatedTime = self:getSteeringRotTimeByCurvature(1 / turnRadius)
811
812 local axisSide
813 if rotatedTime > 0 then
814 axisSide = rotatedTime / -self.maxRotTime
815 else
816 axisSide = rotatedTime / self.minRotTime
817 end
818
819 axisSide = self:getSteeringDirection() * axisSide
820
821 self.spec_drivable.axisSide = axisSide
822end

createAgent

Description
Definition
createAgent()
Code
300function AIDrivable:createAgent(helperIndex)
301 if self.isServer then
302 local spec = self.spec_aiDrivable
303
304 -- first update the ai attachments which may have influence on the agent size
305 self:updateAIAgentAttachments()
306 local trailerData = spec.attachmentsTrailerOffsetData
307
308 local navigationMapId = g_currentMission.aiSystem:getNavigationMap()
309 local agent = spec.agentInfo
310 local width, length, lengthOffset, frontOffset = self:getAIAgentSize()
311 local maxBrakeAcceleration = self:getAIAgentMaxBrakeAcceleration()
312 local maxCentripedalAcceleration = agent.maxCentripedalAcceleration
313 local minTurningRadius = self:getAITurningRadius(agent.maxTurningRadius or self.maxTurningRadius)
314 local minLandingTurningRadius = minTurningRadius -- turning radius limit used when approaching the goal
315 local allowBackwards = self:getAIAllowsBackwards()
316
317 spec.agentId = createVehicleNavigationAgent(navigationMapId, minTurningRadius, minLandingTurningRadius, allowBackwards, width, length, lengthOffset, frontOffset, maxBrakeAcceleration, maxCentripedalAcceleration, trailerData)
318
319 self:setAIVehicleObstacleStateDirty()
320
321 if g_currentMission.aiSystem.debugEnabled then
322 if spec.debugVehicle ~= nil then
323 spec.debugVehicle:delete()
324 end
325 spec.debugVehicle = AIDebugVehicle.new(self, {math.random(), math.random(), math.random()})
326
327 if spec.debugDump ~= nil then
328 spec.debugDump:delete()
329 end
330
331 spec.debugDump = AIDebugDump.new(self, spec.agentId)
332 spec.debugDump:startRecording(minTurningRadius, allowBackwards, width, length, lengthOffset, frontOffset, maxBrakeAcceleration, maxCentripedalAcceleration)
333 end
334 if VehicleDebug.state == VehicleDebug.DEBUG_AI then
335 enableVehicleNavigationAgentDebugRendering(spec.agentId, true)
336 end
337 end
338end

deleteAgent

Description
Definition
deleteAgent()
Code
342function AIDrivable:deleteAgent()
343 local spec = self.spec_aiDrivable
344
345 spec.isRunning = false
346 self:setCruiseControlState(Drivable.CRUISECONTROL_STATE_OFF, true)
347
348 if spec.debugDump ~= nil then
349 spec.debugDump:delete()
350 spec.debugDump = nil
351 end
352
353 if spec.agentId ~= nil then
354 delete(spec.agentId)
355 spec.agentId = nil
356 end
357
358 self:setAIVehicleObstacleStateDirty()
359end

drawDebugAIAgent

Description
Definition
drawDebugAIAgent()
Code
487function AIDrivable:drawDebugAIAgent()
488 local spec = self.spec_aiDrivable
489 local aiRootNode = self:getAIRootNode()
490 local groundOffset = 0.05
491
492 local width, length, lengthOffset, frontOffset, height = self:getAIAgentSize()
493 spec.debugSizeBox:createWithNode(aiRootNode, width*0.5, height*0.5, length*0.5, 0, height*0.5, lengthOffset)
494 spec.debugSizeBox:draw()
495
496 local fx, _, fz = localToWorld(aiRootNode, 0, 0, frontOffset)
497 local dirX, dirY, dirZ = localDirectionToWorld(aiRootNode, 0, 0, 1)
498 local upX, upY, upZ = localDirectionToWorld(aiRootNode, 0, 1, 0)
499 local fy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, fx, 0, fz) + 0.05
500 spec.debugFrontMarker:createWithWorldPosAndDir(fx, fy, fz, dirX, dirY, dirZ, upX, upY, upZ, "FrontMarker", false, nil, 3)
501 spec.debugFrontMarker:draw()
502
503 local x, y, z = getWorldTranslation(aiRootNode)
504 if spec.isRunning then
505 local text
506 if spec.useManualDriving then
507 text = string.format("Distance: %.2f", spec.distanceToTarget)
508 else
509 text = AIDrivable.STATES[spec.lastState]
510 end
511
512 Utils.renderTextAtWorldPosition(x, y + 4, z, text , 0.015, 0, {1, 1, 1, 1})
513 end
514
515 if spec.debugVehicle ~= nil then
516 spec.debugVehicle:draw(y + 0.1)
517 end
518
519 local sx, _, sz = localToWorld(aiRootNode, 0, 0.2, 0)
520 local lx, _, lz = localToWorld(aiRootNode, 20, 0.2, 0)
521 local rx, _, rz = localToWorld(aiRootNode, -20, 0.2, 0)
522
523 local sy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, sx, 0, sz) + groundOffset
524 local ly = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, lx, 0, lz) + groundOffset
525 local ry = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, rx, 0, rz) + groundOffset
526
527 drawDebugLine(sx, sy, sz, 1, 0, 0, lx, ly, lz, 1, 0, 0)
528 drawDebugLine(sx, sy, sz, 0, 1, 0, rx, ry, rz, 0, 1, 0)
529
530 local dirX1, dirZ1 = MathUtil.vector2Normalize(lx-sx, lz-sz)
531 local maxTurningRadius = self.maxTurningRadius
532 local currentTurnRadius = self:getTurningRadiusByRotTime(self.rotatedTime)
533 local minRadius = self:getAITurningRadius(self.maxTurningRadius)
534
535 local revTime = self:getSteeringRotTimeByCurvature(1 / (currentTurnRadius * (self.rotatedTime >= 0 and 1 or -1)))
536
537 local debugString = string.format("ReferenceRadius: %.3fm\nMinRadius: %.3fm\nCalc Radius: %.3f\nRotatedTime: %.3f\nRevTime: %.3f", currentTurnRadius, maxTurningRadius, minRadius, self.rotatedTime, revTime)
538 Utils.renderTextAtWorldPosition(sx, sy + 5, sz, debugString, getCorrectTextSize(0.012), 0)
539
540 local wheelSpec = self.spec_wheels
541 for _, wheel in ipairs(wheelSpec.wheels) do
542 local wsx, _, wsz = localToWorld(wheel.driveNode, 0, 0, 0)
543 local wlx, _, wlz = localToWorld(wheel.driveNode, 20, 0, 0)
544 local wrx, _, wrz = localToWorld(wheel.driveNode, -20, 0, 0)
545 local wsy = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wsx, 0, wsz) + groundOffset
546 local wly = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wlx, 0, wlz) + groundOffset
547 local wry = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wrx, 0, wrz) + groundOffset
548 drawDebugLine(wsx, wsy, wsz, 1, 0, 0, wlx, wly, wlz, 1, 0, 0)
549 drawDebugLine(wsx, wsy, wsz, 0, 1, 0, wrx, wry, wrz, 0, 1, 0)
550
551-- Utils.renderTextAtWorldPosition(wsx, wsy+5, wsz, string.format("RotMin/Max: %.3f / %.3f\nSpeed: %.3f/%.3f", math.deg(wheel.rotMin), math.deg(wheel.rotMax), wheel.rotSpeed, wheel.rotSpeedNeg), getCorrectTextSize(0.012), 0)
552 end
553
554 if wheelSpec.steeringCenterNode ~= nil then
555 DebugUtil.drawDebugNode(wheelSpec.steeringCenterNode, "SCN", false, nil)
556 end
557
558 local sign = MathUtil.sign(self.rotatedTime)
559 local cx, cz = sx + sign*dirX1*currentTurnRadius, sz + sign*dirZ1*currentTurnRadius
560 DebugUtil.drawDebugGizmoAtWorldPos(cx, sy, cz, dirX1, 0, dirZ1, 0, 1, 0, "X", false, nil, 3)
561end

getAIAgentMaxBrakeAcceleration

Description
Definition
getAIAgentMaxBrakeAcceleration()
Code
615function AIDrivable:getAIAgentMaxBrakeAcceleration()
616 local spec = self.spec_aiDrivable
617 local agent = spec.agentInfo
618 return agent.maxBrakeAcceleration
619end

getAIAgentSize

Description
Definition
getAIAgentSize()
Code
598function AIDrivable:getAIAgentSize()
599 local spec = self.spec_aiDrivable
600 local agent = spec.agentInfo
601
602 local width = math.max(agent.width, spec.attachmentsMaxWidth)
603 local height = math.max(agent.height, spec.attachmentsMaxHeight)
604 local length = agent.length
605 local lengthOffset = agent.lengthOffset
606
607 length = length + spec.attachmentsMaxLengthOffsetPos - spec.attachmentsMaxLengthOffsetNeg
608 lengthOffset = lengthOffset + spec.attachmentsMaxLengthOffsetPos * 0.5 + spec.attachmentsMaxLengthOffsetNeg * 0.5
609
610 return width, length, lengthOffset, agent.frontOffset, height
611end

getAIAllowsBackwards

Description
Definition
getAIAllowsBackwards()
Code
429function AIDrivable:getAIAllowsBackwards()
430 return false
431end

getAIRootNode

Description
Definition
getAIRootNode()
Code
423function AIDrivable:getAIRootNode()
424 return self.components[1].node
425end

getAITurningRadius

Description
Definition
getAITurningRadius()
Code
782function AIDrivable:getAITurningRadius(minRadius)
783 return minRadius
784end

getIsAIPreparingToDrive

Description
Definition
getIsAIPreparingToDrive()
Code
471function AIDrivable:getIsAIPreparingToDrive(superFunc)
472 for _, vehicle in ipairs(self.rootVehicle.childVehicles) do
473 if vehicle ~= self then
474 if vehicle.getIsAIPreparingToDrive ~= nil then
475 if vehicle:getIsAIPreparingToDrive() then
476 return true
477 end
478 end
479 end
480 end
481
482 return superFunc(self)
483end

getIsAIReadyToDrive

Description
Definition
getIsAIReadyToDrive()
Code
455function AIDrivable:getIsAIReadyToDrive(superFunc)
456 for _, vehicle in ipairs(self.rootVehicle.childVehicles) do
457 if vehicle ~= self then
458 if vehicle.getIsAIReadyToDrive ~= nil then
459 if not vehicle:getIsAIReadyToDrive() then
460 return false, vehicle
461 end
462 end
463 end
464 end
465
466 return superFunc(self)
467end

initSpecialization

Description
Definition
initSpecialization()
Code
33function AIDrivable.initSpecialization()
34 local schema = Vehicle.xmlSchema
35 schema:setXMLSpecializationType("AI")
36 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#width", "AI vehicle width")
37 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#length", "AI vehicle length")
38 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#lengthOffset", "AI vehicle length offset")
39 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#height", "AI vehicle height")
40 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#frontOffset", "AI vehicle front offset")
41 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#maxBrakeAcceleration", "AI vehicle max brake acceleration")
42 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#maxCentripedalAcceleration", "AI vehicle max centripedal acceleration")
43 schema:register(XMLValueType.FLOAT, "vehicle.ai.agent#maxTurningRadius", "Max. turning radius (overwrites value detected from ackermann steering)")
44 schema:setXMLSpecializationType()
45end

loadAgentInfoFromXML

Description
Definition
loadAgentInfoFromXML()
Code
565function AIDrivable:loadAgentInfoFromXML(xmlFile, agent)
566 local baseSizeKey = "vehicle.ai.agent"
567 agent.width = xmlFile:getValue(baseSizeKey .. "#width", Vehicle.DEFAULT_SIZE.width)
568 agent.length = xmlFile:getValue(baseSizeKey .. "#length", Vehicle.DEFAULT_SIZE.length)
569 agent.height = xmlFile:getValue(baseSizeKey .. "#height", Vehicle.DEFAULT_SIZE.height)
570 agent.lengthOffset = xmlFile:getValue(baseSizeKey .. "#lengthOffset", Vehicle.DEFAULT_SIZE.lengthOffset)
571 agent.frontOffset = xmlFile:getValue(baseSizeKey .. "#frontOffset", 3)
572 agent.maxBrakeAcceleration = xmlFile:getValue(baseSizeKey .. "#maxBrakeAcceleration", 5)
573 agent.maxCentripedalAcceleration = xmlFile:getValue(baseSizeKey .. "#maxCentripedalAcceleration", 1)
574 agent.maxTurningRadius = xmlFile:getValue(baseSizeKey .. "#maxTurningRadius")
575
576 -- check configurations for changed agent values
577 for name, id in pairs(self.configurations) do
578 local specializationKey = g_configurationManager:getConfigurationAttribute(name, "xmlKey")
579 if specializationKey ~= nil then
580 specializationKey = "." .. specializationKey
581 else
582 specializationKey = ""
583 end
584 local key = string.format("vehicle%s.%sConfigurations.%sConfiguration(%d).aiAgent", specializationKey, name, name , id - 1)
585 agent.width = math.max(agent.width, xmlFile:getValue(key .. "#width", 0))
586 agent.length = math.max(agent.length, xmlFile:getValue(key .. "#length", 0))
587 agent.height = math.max(agent.height, xmlFile:getValue(key .. "#height", 0))
588 agent.lengthOffset = xmlFile:getValue(key .. "#lengthOffset", agent.lengthOffset)
589 agent.frontOffset = xmlFile:getValue(key .. "#frontOffset", agent.frontOffset)
590 agent.maxBrakeAcceleration = math.min(xmlFile:getValue(key .. "#maxBrakeAcceleration", agent.maxBrakeAcceleration))
591 agent.maxCentripedalAcceleration = math.min(xmlFile:getValue(key .. "#maxCentripedalAcceleration", agent.maxCentripedalAcceleration))
592 agent.maxTurningRadius = xmlFile:getValue(key .. "#maxTurningRadius", agent.maxTurningRadius)
593 end
594end

onDelete

Description
Definition
onDelete()
Code
193function AIDrivable:onDelete()
194 local spec = self.spec_aiDrivable
195end

onEnterVehicle

Description
Definition
onEnterVehicle()
Code
435function AIDrivable:onEnterVehicle(isControlling)
436 if isControlling then
437 addConsoleCommand("gsAISetTurnRadius", "Set Turn radius", "consoleCommandSetTurnRadius", self)
438 addConsoleCommand("gsAIMoveVehicle", "Moves vehicles", "consoleCommandMove", self)
439 addConsoleCommand("gsAIClearPath", "Clears debug path", "consoleCommandClearPath", self)
440 end
441end

onLeaveVehicle

Description
Definition
onLeaveVehicle()
Code
445function AIDrivable:onLeaveVehicle(wasEntered)
446 if wasEntered then
447 removeConsoleCommand("gsAISetTurnRadius")
448 removeConsoleCommand("gsAIMoveVehicle")
449 removeConsoleCommand("gsAIClearPath")
450 end
451end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
133function AIDrivable:onLoad(savegame)
134 local spec = self.spec_aiDrivable
135
136 spec.agentInfo = {}
137 self:loadAgentInfoFromXML(self.xmlFile, spec.agentInfo)
138
139 spec.maxSpeed = math.huge
140 spec.isRunning = false
141 spec.useManualDriving = false
142 spec.lastState = nil
143 spec.lastIsBlocked = false
144 spec.lastMaxSpeed = 0
145 spec.stuckTime = 0
146 spec.agentId = nil
147 spec.targetX, spec.targetY, spec.targetZ = nil, nil, nil
148 spec.targetDirX, spec.targetDirY, spec.targetDirZ = nil, nil, nil
149
150 spec.attachments = {}
151 spec.attachmentChains = {}
152 spec.attachmentChainIndex = 1
153 spec.attachmentsTrailerOffsetData = {}
154 spec.attachmentsMaxWidth = 0
155 spec.attachmentsMaxHeight = 0
156 spec.attachmentsMaxLengthOffsetPos = 0
157 spec.attachmentsMaxLengthOffsetNeg = 0
158
159 spec.poseData = {}
160
161 spec.vehicleObstacleId = nil
162
163 spec.debugVehicle = nil
164 spec.debugSizeBox = DebugCube.new()
165 spec.debugSizeBox:setColor(0, 1, 1)
166
167 spec.debugFrontMarker = DebugGizmo.new()
168 spec.debugDump = nil
169end

onPostLoad

Description
Definition
onPostLoad()
Code
173function AIDrivable:onPostLoad()
174 local spec = self.spec_aiDrivable
175
176 local aiRootNode = self:getAIRootNode()
177
178 spec.attacherJointOffsets = {}
179 if self.getAttacherJoints ~= nil then
180 for _, attacherJoint in ipairs(self:getAttacherJoints()) do
181 local node = attacherJoint.jointTransform
182 local xDir, yDir, zDir = localDirectionToLocal(node, aiRootNode, 0, 0, 1)
183 local xUp, yUp, zUp = localDirectionToLocal(node, aiRootNode, 0, 1, 0)
184 local x, y, z = localToLocal(node, aiRootNode, 0, 0, 0)
185
186 table.insert(spec.attacherJointOffsets, {x=x, y=y, z=z, xDir=xDir, yDir=yDir, zDir=zDir, xUp=xUp, yUp=yUp, zUp=zUp})
187 end
188 end
189end

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
202function AIDrivable:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
203 local spec = self.spec_aiDrivable
204
205 if self.isServer then
206 if spec.isRunning then
207
208 -- if vehicle was blocked in the last frame we want to keep the block state as long as last speed < 4kmh
209 -- to avoid issues with set block or unblock each frame
210 local isStillBlocked = spec.lastIsBlocked and self:getLastSpeed() < 5
211 -- check if vehicle is currently blocked
212 local isCurrentlyBlocked = math.abs(spec.lastMaxSpeed) > 0 and self:getLastSpeed() < 1
213
214 if isCurrentlyBlocked or isStillBlocked then
215 spec.stuckTime = spec.stuckTime + dt
216 else
217 spec.stuckTime = 0
218 end
219
220 local isBlocked = spec.stuckTime > 5000
221
222 local aiRootNode = self:getAIRootNode()
223 local x, y, z = getWorldTranslation(aiRootNode)
224 spec.distanceToTarget = MathUtil.vector2Length(x - spec.targetX, z - spec.targetZ)
225 local lastSpeed = self.lastSpeedReal * self.movingDirection * 1000
226
227 local maxSpeed = math.min(spec.maxSpeed, self:getCruiseControlSpeed())
228
229 if spec.useManualDriving then
230 local tx, _, tz = worldToLocal(aiRootNode, spec.targetX, spec.targetY, spec.targetZ)
231
232 AIVehicleUtil.driveToPoint(self, dt, 1, true, true, tx, tz, maxSpeed, false)
233
234 spec.lastMaxSpeed = maxSpeed
235
236 if spec.distanceToTarget < 0.5 then
237 self:reachedAITarget()
238 end
239 else
240 local dirX, dirY, dirZ = localDirectionToWorld(aiRootNode, 0, 0, 1)
241
242 self:updateAIAgentPoseData()
243
244 local curvature, maxSpeedCurvature, status = getVehicleNavigationAgentNextCurvature(spec.agentId, spec.poseData, lastSpeed)
245
246 if spec.debugDump ~= nil then
247 spec.debugDump:addData(dt, x, y, z, dirX, dirY, dirZ, lastSpeed, curvature, maxSpeed, status)
248 end
249
250 -- update driving
251 if status == AgentState.DRIVING then
252 maxSpeed = math.min(maxSpeedCurvature * 3.6, maxSpeed)
253 AIVehicleUtil.driveAlongCurvature(self, dt, curvature, maxSpeed, 1)
254 if maxSpeed == 0 then
255 isBlocked = false
256 end
257 elseif status == AgentState.PLANNING then
258 isBlocked = false
259 self:brake(1)
260 elseif status == AgentState.BLOCKED then
261 isBlocked = true
262 self:brake(1)
263 elseif status == AgentState.TARGET_REACHED then
264 isBlocked = false
265 self:reachedAITarget()
266 elseif status == AgentState.NOT_REACHABLE then
267 isBlocked = false
268 self:stopCurrentAIJob(AIMessageErrorNotReachable.new())
269 end
270
271 spec.lastState = status
272 spec.lastMaxSpeed = maxSpeed
273 end
274
275 if spec.debugVehicle ~= nil then
276 spec.debugVehicle:update(dt)
277 end
278
279 if isBlocked and not spec.lastIsBlocked then
280 g_server:broadcastEvent(AIVehicleIsBlockedEvent.new(self, true), true, nil, self)
281 elseif not isBlocked and spec.lastIsBlocked then
282 g_server:broadcastEvent(AIVehicleIsBlockedEvent.new(self, false), true, nil, self)
283 end
284
285 spec.lastIsBlocked = isBlocked
286
287 SpecializationUtil.raiseEvent(self, "onAIDriveableActive")
288 end
289
290 if spec.vehicleObstacleId ~= nil then
291 local speed = self.lastSpeedReal * 1000
292 local poses = self:getAIAgentPoses(speed)
293 g_currentMission.aiSystem:setVehiclObstaclePose(spec.vehicleObstacleId, speed, poses)
294 end
295 end
296end

postInitSpecialization

Description
Definition
postInitSpecialization()
Code
49function AIDrivable.postInitSpecialization()
50 local schema = Vehicle.xmlSchema
51 for name, _ in pairs(g_configurationManager:getConfigurations()) do
52 local specializationKey = g_configurationManager:getConfigurationAttribute(name, "xmlKey")
53 if specializationKey ~= nil then
54 specializationKey = "." .. specializationKey
55 else
56 specializationKey = ""
57 end
58
59 local configrationsKey = string.format("vehicle%s.%sConfigurations", specializationKey, name)
60 local configrationKey = string.format("%s.%sConfiguration(?)", configrationsKey, name)
61
62 schema:setXMLSharedRegistration("configAIAgent", configrationKey)
63 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#width", "ai width of the vehicle when loaded in this configuration")
64 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#length", "ai length of the vehicle when loaded in this configuration")
65 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#height", "ai height of the vehicle when loaded in this configuration")
66 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#lengthOffset", "length offset")
67 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#frontOffset", "front offset")
68 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#maxBrakeAcceleration", "AI vehicle max brake acceleration")
69 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#maxCentripedalAcceleration", "AI vehicle max centripedal acceleration")
70 schema:register(XMLValueType.FLOAT, configrationKey .. ".aiAgent#maxTurningRadius", "Max. turning radius (overwrites value detected from ackermann steering)")
71 schema:setXMLSharedRegistration()
72 end
73end

prepareForAIDriving

Description
Definition
prepareForAIDriving()
Code
776function AIDrivable:prepareForAIDriving()
777 self:raiseAIEvent("onAIDrivablePrepare", "onAIImplementPrepare")
778end

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
25function AIDrivable.prerequisitesPresent(specializations)
26 return SpecializationUtil.hasSpecialization(AIVehicle, specializations) and
27 SpecializationUtil.hasSpecialization(AIJobVehicle, specializations) and
28 SpecializationUtil.hasSpecialization(Drivable, specializations)
29end

reachedAITarget

Description
Definition
reachedAITarget()
Code
396function AIDrivable:reachedAITarget()
397 local spec = self.spec_aiDrivable
398 if self.isServer then
399 local lastTask = spec.task
400 if lastTask ~= nil then
401 lastTask:onTargetReached()
402 end
403 end
404end

registerEventListeners

Description
Definition
registerEventListeners()
Code
121function AIDrivable.registerEventListeners(vehicleType)
122 SpecializationUtil.registerEventListener(vehicleType, "onLoad", AIDrivable)
123 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", AIDrivable)
124 SpecializationUtil.registerEventListener(vehicleType, "onDelete", AIDrivable)
125 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", AIDrivable)
126 SpecializationUtil.registerEventListener(vehicleType, "onEnterVehicle", AIDrivable)
127 SpecializationUtil.registerEventListener(vehicleType, "onLeaveVehicle", AIDrivable)
128end

registerEvents

Description
Definition
registerEvents()
Code
77function AIDrivable.registerEvents(vehicleType)
78 SpecializationUtil.registerEvent(vehicleType, "onAIDrivablePrepare")
79 SpecializationUtil.registerEvent(vehicleType, "onAIDriveableStart")
80 SpecializationUtil.registerEvent(vehicleType, "onAIDriveableActive")
81 SpecializationUtil.registerEvent(vehicleType, "onAIDriveableEnd")
82end

registerFunctions

Description
Definition
registerFunctions()
Code
87function AIDrivable.registerFunctions(vehicleType)
88 SpecializationUtil.registerFunction(vehicleType, "consoleCommandSetTurnRadius", AIDrivable.consoleCommandSetTurnRadius)
89 SpecializationUtil.registerFunction(vehicleType, "consoleCommandMove", AIDrivable.consoleCommandMove)
90 SpecializationUtil.registerFunction(vehicleType, "consoleCommandClearPath", AIDrivable.consoleCommandClearPath)
91 SpecializationUtil.registerFunction(vehicleType, "createAgent", AIDrivable.createAgent)
92 SpecializationUtil.registerFunction(vehicleType, "deleteAgent", AIDrivable.deleteAgent)
93 SpecializationUtil.registerFunction(vehicleType, "setAITarget", AIDrivable.setAITarget)
94 SpecializationUtil.registerFunction(vehicleType, "unsetAITarget", AIDrivable.unsetAITarget)
95 SpecializationUtil.registerFunction(vehicleType, "reachedAITarget", AIDrivable.reachedAITarget)
96 SpecializationUtil.registerFunction(vehicleType, "getAIRootNode", AIDrivable.getAIRootNode)
97 SpecializationUtil.registerFunction(vehicleType, "getAIAllowsBackwards", AIDrivable.getAIAllowsBackwards)
98 SpecializationUtil.registerFunction(vehicleType, "drawDebugAIAgent", AIDrivable.drawDebugAIAgent)
99 SpecializationUtil.registerFunction(vehicleType, "loadAgentInfoFromXML", AIDrivable.loadAgentInfoFromXML)
100 SpecializationUtil.registerFunction(vehicleType, "getAIAgentSize", AIDrivable.getAIAgentSize)
101 SpecializationUtil.registerFunction(vehicleType, "getAIAgentMaxBrakeAcceleration", AIDrivable.getAIAgentMaxBrakeAcceleration)
102 SpecializationUtil.registerFunction(vehicleType, "updateAIAgentAttachments", AIDrivable.updateAIAgentAttachments)
103 SpecializationUtil.registerFunction(vehicleType, "addAIAgentAttachment", AIDrivable.addAIAgentAttachment)
104 SpecializationUtil.registerFunction(vehicleType, "startNewAIAgentAttachmentChain", AIDrivable.startNewAIAgentAttachmentChain)
105 SpecializationUtil.registerFunction(vehicleType, "updateAIAgentAttachmentOffsetData", AIDrivable.updateAIAgentAttachmentOffsetData)
106 SpecializationUtil.registerFunction(vehicleType, "updateAIAgentPoseData", AIDrivable.updateAIAgentPoseData)
107 SpecializationUtil.registerFunction(vehicleType, "prepareForAIDriving", AIDrivable.prepareForAIDriving)
108 SpecializationUtil.registerFunction(vehicleType, "getAITurningRadius", AIDrivable.getAITurningRadius)
109end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
113function AIDrivable.registerOverwrittenFunctions(vehicleType)
114 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanHaveAIVehicleObstacle", AIDrivable.getCanHaveAIVehicleObstacle)
115 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAIReadyToDrive", AIDrivable.getIsAIReadyToDrive)
116 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAIPreparingToDrive", AIDrivable.getIsAIPreparingToDrive)
117end

setAITarget

Description
Definition
setAITarget()
Code
363function AIDrivable:setAITarget(task, x, y, z, dirX, dirY, dirZ, maxSpeed, useManualDriving)
364 local spec = self.spec_aiDrivable
365
366 local aiRootNode = self:getAIRootNode()
367 local cx, cy, cz = getWorldTranslation(aiRootNode)
368 local cDirX, cDirY, cDirZ = localDirectionToWorld(aiRootNode, 0, 0, 1)
369
370 spec.useManualDriving = Utils.getNoNil(useManualDriving, false)
371
372 spec.isRunning = true
373 spec.task = task
374 spec.maxSpeed = maxSpeed or math.huge
375 spec.targetX, spec.targetY, spec.targetZ = x, y, z
376 spec.targetDirX, spec.targetDirY, spec.targetDirZ = dirX or 0, dirY, dirZ or 0
377 spec.distanceToTarget = MathUtil.vector2Length(cx-x, cz-z)
378
379 if not spec.useManualDriving and self.isServer then
380 setVehicleNavigationAgentTarget(spec.agentId, x, y, z, dirX, dirY, dirZ)
381 end
382
383 if spec.debugVehicle ~= nil then
384 spec.debugVehicle:setTarget(x, y, z, dirX, dirY, dirZ)
385 end
386
387 if spec.debugDump ~= nil then
388 spec.debugDump:setTarget(x, y, z, dirX, dirY, dirZ, cx, cy, cz, cDirX, cDirY, cDirZ, spec.maxSpeed)
389 end
390
391 SpecializationUtil.raiseEvent(self, "onAIDriveableStart")
392end

startNewAIAgentAttachmentChain

Description
Definition
startNewAIAgentAttachmentChain()
Code
661function AIDrivable:startNewAIAgentAttachmentChain()
662 local spec = self.spec_aiDrivable
663 if spec.attachmentChains[spec.attachmentChainIndex] ~= nil then
664 spec.attachmentChainIndex = spec.attachmentChainIndex + 1
665 end
666end

unsetAITarget

Description
Definition
unsetAITarget()
Code
408function AIDrivable:unsetAITarget()
409 local spec = self.spec_aiDrivable
410 spec.isRunning = false
411 spec.task = nil
412 spec.useManualDriving = false
413
414 self:brake(1)
415 self:stopVehicle()
416 self:setCruiseControlState(Drivable.CRUISECONTROL_STATE_OFF, true)
417
418 SpecializationUtil.raiseEvent(self, "onAIDriveableEnd")
419end

updateAIAgentAttachmentOffsetData

Description
Definition
updateAIAgentAttachmentOffsetData()
Code
670function AIDrivable:updateAIAgentAttachmentOffsetData()
671 local spec = self.spec_aiDrivable
672 local _, agentLength, lengthOffset, _ = self:getAIAgentSize()
673 local numTrailers = 0
674 for ci=1, #spec.attachmentChains do
675 local chainAttachments = spec.attachmentChains[ci]
676 local isDynamicChain = true
677 local isStaticChain = true
678
679 local parentSteeringCenterNode = self.components[1].node
680 local parentSteeringCenterOffsetZ = lengthOffset
681 for i=1, #chainAttachments do
682 local agentAttachment = chainAttachments[i]
683 if agentAttachment.rotCenterNode ~= nil and isDynamicChain then
684 if numTrailers < AIDrivable.TRAILER_LIMIT then
685 local jointNode = agentAttachment.jointNode or agentAttachment.jointNodeDynamic
686 local attacherVehicleJointNode = agentAttachment.attacherVehicleJointNode or jointNode
687 if attacherVehicleJointNode ~= nil and jointNode ~= nil then
688 local x1, _, z1 = getWorldTranslation(attacherVehicleJointNode)
689 local x2, _, z2 = localToWorld(parentSteeringCenterNode, 0, 0, -parentSteeringCenterOffsetZ)
690 local tractorHitchOffset = -MathUtil.vector2Length(x1-x2, z1-z2)
691
692 x1, _, z1 = getWorldTranslation(jointNode)
693 x2, _, z2 = getWorldTranslation(agentAttachment.rotCenterNode)
694 local trailerHitchOffset = MathUtil.vector2Length(x1-x2, z1-z2)
695
696 -- TODO: still wip until fixed in the engine
697 local centerOffset = agentAttachment.lengthOffset + (agentLength * 0.5) - (agentAttachment.length * 0.5)
698 local hasCollision = 0-- agentAttachment.hasCollision and 1 or 0
699
700 table.insert(spec.attachmentsTrailerOffsetData, tractorHitchOffset)
701 table.insert(spec.attachmentsTrailerOffsetData, trailerHitchOffset)
702 table.insert(spec.attachmentsTrailerOffsetData, centerOffset)
703 table.insert(spec.attachmentsTrailerOffsetData, hasCollision)
704
705 parentSteeringCenterNode = agentAttachment.rotCenterNode
706 parentSteeringCenterOffsetZ = 0
707 numTrailers = numTrailers + 1
708 end
709 isStaticChain = false
710 end
711 elseif isStaticChain then
712 if numTrailers > 0 then
713 isDynamicChain = false
714 end
715
716 if agentAttachment.rotCenterNode == nil then
717 local aiRootNode = self:getAIRootNode()
718 local _, _, z1 = localToLocal(agentAttachment.rootNode, aiRootNode, 0, 0, agentAttachment.length * 0.5)
719 local _, _, z2 = localToLocal(agentAttachment.rootNode, aiRootNode, 0, 0, -agentAttachment.length * 0.5)
720
721 local minZ = -spec.agentInfo.length * 0.5 + spec.agentInfo.lengthOffset
722 local maxZ = spec.agentInfo.length * 0.5 + spec.agentInfo.lengthOffset
723 local zDiffNeg = math.min(0, z1 - minZ, z2 - minZ)
724 local zDiffPos = math.max(0, z1 - maxZ, z2 - maxZ)
725
726 spec.attachmentsMaxLengthOffsetPos = math.max(spec.attachmentsMaxLengthOffsetPos, zDiffPos)
727 spec.attachmentsMaxLengthOffsetNeg = math.min(spec.attachmentsMaxLengthOffsetNeg, zDiffNeg)
728 end
729 end
730 end
731 end
732end

updateAIAgentAttachments

Description
Definition
updateAIAgentAttachments()
Code
623function AIDrivable:updateAIAgentAttachments()
624 local spec = self.spec_aiDrivable
625
626 spec.attachments = {}
627 spec.attachmentChains = {}
628 spec.attachmentChainIndex = 1
629 spec.attachmentsTrailerOffsetData = {}
630 spec.attachmentsMaxWidth = 0
631 spec.attachmentsMaxHeight = 0
632
633 spec.attachmentsMaxLengthOffsetPos = 0
634 spec.attachmentsMaxLengthOffsetNeg = 0
635
636 self:collectAIAgentAttachments(self)
637 self:updateAIAgentAttachmentOffsetData()
638 self:updateAIAgentPoseData()
639end

updateAIAgentPoseData

Description
Definition
updateAIAgentPoseData()
Code
736function AIDrivable:updateAIAgentPoseData()
737 local spec = self.spec_aiDrivable
738
739 local aiRootNode = self:getAIRootNode()
740
741 spec.poseData[1], spec.poseData[2], spec.poseData[3] = getWorldTranslation(aiRootNode)
742 spec.poseData[4], spec.poseData[5], spec.poseData[6] = localDirectionToWorld(aiRootNode, 0, 0, 1)
743
744 local numTrailers = 0
745 local currentIndex = 6
746
747 for ci=1, #spec.attachmentChains do
748 local chainAttachments = spec.attachmentChains[ci]
749 local isDynamicChain = true
750
751 for i=1, #chainAttachments do
752 local agentAttachment = chainAttachments[i]
753 if agentAttachment.rotCenterNode ~= nil and isDynamicChain then
754 if numTrailers < AIDrivable.TRAILER_LIMIT then
755 spec.poseData[currentIndex + 1], spec.poseData[currentIndex + 2], spec.poseData[currentIndex + 3] = getWorldTranslation(agentAttachment.rotCenterNode)
756 spec.poseData[currentIndex + 4], spec.poseData[currentIndex + 5], spec.poseData[currentIndex + 6] = localDirectionToWorld(agentAttachment.rotCenterNode, 0, 0, 1)
757
758 numTrailers = numTrailers + 1
759 currentIndex = currentIndex + 6
760 end
761 else
762 if numTrailers > 0 then
763 isDynamicChain = false
764 end
765 end
766 end
767 end
768
769 while #spec.poseData > currentIndex do
770 table.remove(spec.poseData, #spec.poseData)
771 end
772end