LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

PlaceableAI

Description
Specialization for placeables
Functions

loadAIObstacle

Description
Definition
loadAIObstacle()
Code
220function PlaceableAI:loadAIObstacle(xmlFile, key, obstacle)
221 obstacle.node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
222 if obstacle.node == nil then
223 Logging.xmlWarning(xmlFile, "Obstacle '%s' node does not exist", key)
224 return false
225 end
226
227 obstacle.size = xmlFile:getValue(key .. "#size", "0 0 0", true)
228 obstacle.offset = xmlFile:getValue(key .. "#offset", "0 0 0", true)
229
230 -- size can only be omitted if node is a rigid body / has a collision box
231 if getRigidBodyType(obstacle.node) == RigidBodyType.NONE and obstacle.size[1] == 0 then
232 Logging.xmlWarning(xmlFile, "Obstacle '%s' is not a rigid body and needs a size", key)
233 return false
234 end
235
236 obstacle.animatedObjectIndex = xmlFile:getValue(key .. ".animatedObject#index")
237 if obstacle.animatedObjectIndex == nil then
238 Logging.xmlWarning(xmlFile, "Obstacle '%s' is missing animated object index", key)
239 return false
240 end
241
242 obstacle.animatedObjectTimeStart = xmlFile:getValue(key .. ".animatedObject#startTime")
243 obstacle.animatedObjectTimeEnd = xmlFile:getValue(key .. ".animatedObject#endTime")
244
245 if obstacle.animatedObjectTimeStart == nil or obstacle.animatedObjectTimeEnd == nil then
246 Logging.xmlWarning(xmlFile, "Obstacle '%s' is missing start or end time", key)
247 return false
248 end
249
250 if obstacle.animatedObjectTimeStart >= obstacle.animatedObjectTimeEnd then
251 Logging.xmlWarning(xmlFile, "Obstacle '%s' start time need to be smaller than end time", key)
252 return false
253 end
254
255 obstacle.isActive = false
256
257 return true
258end

loadAISpline

Description
Definition
loadAISpline()
Code
199function PlaceableAI:loadAISpline(xmlFile, key, spline)
200 local splineNode = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
201
202 if splineNode == nil then
203 return false
204 end
205
206 setVisibility(splineNode, false)
207
208 local maxWidth = xmlFile:getValue(key .. "#maxWidth")
209 local maxTurningRadius = xmlFile:getValue(key .. "#maxTurningRadius")
210
211 spline.splineNode = splineNode
212 spline.maxWidth = maxWidth
213 spline.maxTurningRadius = maxTurningRadius
214
215 return true
216end

loadAIUpdateArea

Description
Definition
loadAIUpdateArea()
Code
162function PlaceableAI:loadAIUpdateArea(xmlFile, key, area)
163 local startNode = xmlFile:getValue(key .. "#startNode", nil, self.components, self.i3dMappings)
164 local endNode = xmlFile:getValue(key .. "#endNode", nil, self.components, self.i3dMappings)
165
166 if startNode == nil then
167 Logging.xmlWarning(xmlFile, "Missing ai update area start node for '%s'", key)
168 return false
169 end
170
171 if endNode == nil then
172 Logging.xmlWarning(xmlFile, "Missing ai update area end node for '%s'", key)
173 return false
174 end
175
176
177 local startX, _, startZ = localToLocal(startNode, self.rootNode, 0, 0, 0)
178 local endX, _, endZ = localToLocal(endNode, self.rootNode, 0, 0, 0)
179
180 local sizeX = math.abs(endX - startX)
181 local sizeZ = math.abs(endZ - startZ)
182
183 area.center = {}
184 area.center.x = (endX + startX) * 0.5
185 area.center.z = (endZ + startZ) * 0.5
186
187 area.size = {}
188 area.size.x = sizeX
189 area.size.z = sizeZ
190
191 area.startNode = startNode
192 area.endNode = endNode
193
194 return true
195end

onDelete

Description
Definition
onDelete()
Code
132function PlaceableAI:onDelete()
133 if self.isServer then
134 local spec = self.spec_ai
135 if spec.updateAreaOnDelete then
136 self:updateAIUpdateAreas()
137 end
138
139 if g_currentMission.aiSystem ~= nil then
140 if spec.splines ~= nil then
141 for _, spline in pairs(spec.splines) do
142 g_currentMission.aiSystem:removeRoadSpline(spline.splineNode)
143 end
144 end
145
146 if self.spec_animatedObjects ~= nil and g_currentMission.aiSystem.navigationMap ~= nil then
147 local animatedObjects = self.spec_animatedObjects.animatedObjects
148 if animatedObjects ~= nil then
149 for _, obstacle in ipairs(spec.obstacles) do
150 if obstacle.isActive then
151 self:setObstacleActive(obstacle, false)
152 end
153 end
154 end
155 end
156 end
157 end
158end

onFinalizePlacement

Description
Definition
onFinalizePlacement()
Code
262function PlaceableAI:onFinalizePlacement()
263 if self.isServer then
264 local spec = self.spec_ai
265 local missionInfo = g_currentMission.missionInfo
266
267 spec.updateAreaOnDelete = true
268
269 if not self.isLoadedFromSavegame or not missionInfo.isValid then
270 self:updateAIUpdateAreas()
271 end
272
273 if g_currentMission.aiSystem ~= nil then
274 for _, spline in ipairs(spec.splines) do
275 g_currentMission.aiSystem:addRoadSpline(spline.splineNode, spline.maxWidth, spline.maxTurningRadius)
276 end
277
278 -- explicitly update state once
279 if g_currentMission.aiSystem.navigationMap ~= nil then
280 for _, obstacle in ipairs(spec.obstacles) do
281 if obstacle.animatedObject ~= nil then
282 obstacle.updateState(nil, obstacle.animatedObject.animation.time)
283 end
284 end
285 end
286 end
287 end
288end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
64function PlaceableAI:onLoad(savegame)
65 local spec = self.spec_ai
66 local xmlFile = self.xmlFile
67
68 spec.updateAreaOnDelete = false
69
70 spec.areas = {}
71 xmlFile:iterate("placeable.ai.updateAreas.updateArea", function(_, key)
72 local area = {}
73 if self:loadAIUpdateArea(xmlFile, key, area) then
74 table.insert(spec.areas, area)
75 end
76 end)
77
78 if not self.xmlFile:hasProperty("placeable.ai.updateAreas") then
79 Logging.xmlWarning(self.xmlFile, "Missing ai update areas")
80 end
81
82 spec.splines = {}
83 xmlFile:iterate("placeable.ai.splines.spline", function(_, key)
84 local spline = {}
85 if self:loadAISpline(xmlFile, key, spline) then
86 table.insert(spec.splines, spline)
87 end
88 end)
89
90 spec.obstacles = {}
91 xmlFile:iterate("placeable.ai.obstacles.obstacle", function(_, key)
92 local obstacle = {}
93 if self:loadAIObstacle(xmlFile, key, obstacle) then
94 table.insert(spec.obstacles, obstacle)
95 end
96 end)
97end

onPostLoad

Description
Definition
onPostLoad()
Code
101function PlaceableAI:onPostLoad(savegame)
102 local spec = self.spec_ai
103 if self.spec_animatedObjects ~= nil and g_currentMission.aiSystem ~= nil and g_currentMission.aiSystem.navigationMap ~= nil then
104 local animatedObjects = self.spec_animatedObjects.animatedObjects
105
106 for obstacleIndex, obstacle in ipairs(spec.obstacles) do
107 local animatedObject = animatedObjects[obstacle.animatedObjectIndex]
108 if animatedObject == nil then
109 Logging.warning("Placeable AI obstacle %d: AnimatedObject with index %d does not exist", obstacleIndex, obstacle.animatedObjectIndex)
110 else
111 obstacle.animatedObject = animatedObject
112 obstacle.updateState = function(_, t, omitSound)
113 if t >= obstacle.animatedObjectTimeStart and t <= obstacle.animatedObjectTimeEnd then
114 if not obstacle.isActive then
115 self:setObstacleActive(obstacle, true)
116 end
117 else
118 if obstacle.isActive then
119 self:setObstacleActive(obstacle, false)
120 end
121 end
122 end
123 -- hook into setAnimTime to add and remove AI obstacle in animation
124 animatedObject.setAnimTime = Utils.appendedFunction(animatedObject.setAnimTime, obstacle.updateState)
125 end
126 end
127 end
128end

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 PlaceableAI.prerequisitesPresent(specializations)
19 return true
20end

registerEventListeners

Description
Definition
registerEventListeners()
Code
34function PlaceableAI.registerEventListeners(placeableType)
35 SpecializationUtil.registerEventListener(placeableType, "onLoad", PlaceableAI)
36 SpecializationUtil.registerEventListener(placeableType, "onPostLoad", PlaceableAI)
37 SpecializationUtil.registerEventListener(placeableType, "onDelete", PlaceableAI)
38 SpecializationUtil.registerEventListener(placeableType, "onFinalizePlacement", PlaceableAI)
39end

registerFunctions

Description
Definition
registerFunctions()
Code
24function PlaceableAI.registerFunctions(placeableType)
25 SpecializationUtil.registerFunction(placeableType, "setObstacleActive", PlaceableAI.setObstacleActive)
26 SpecializationUtil.registerFunction(placeableType, "loadAIUpdateArea", PlaceableAI.loadAIUpdateArea)
27 SpecializationUtil.registerFunction(placeableType, "loadAISpline", PlaceableAI.loadAISpline)
28 SpecializationUtil.registerFunction(placeableType, "loadAIObstacle", PlaceableAI.loadAIObstacle)
29 SpecializationUtil.registerFunction(placeableType, "updateAIUpdateAreas", PlaceableAI.updateAIUpdateAreas)
30end

registerXMLPaths

Description
Definition
registerXMLPaths()
Code
43function PlaceableAI.registerXMLPaths(schema, basePath)
44 schema:setXMLSpecializationType("AI")
45 schema:register(XMLValueType.NODE_INDEX, basePath .. ".ai.updateAreas.updateArea(?)#startNode", "Start node of ai update area")
46 schema:register(XMLValueType.NODE_INDEX, basePath .. ".ai.updateAreas.updateArea(?)#endNode", "End node of ai update area")
47
48 schema:register(XMLValueType.NODE_INDEX, basePath .. ".ai.splines.spline(?)#node", "Spline node or transform group containing splines. Spline direction not relevant")
49 schema:register(XMLValueType.FLOAT, basePath .. ".ai.splines.spline(?)#maxWidth", "Maximum vehicle width supported by the spline")
50 schema:register(XMLValueType.FLOAT, basePath .. ".ai.splines.spline(?)#maxTurningRadius", "Maxmium vehicle turning supported by the spline")
51
52 schema:register(XMLValueType.NODE_INDEX, basePath .. ".ai.obstacles.obstacle(?)#node", "Node to be used for obstacle box", nil, true)
53 schema:register(XMLValueType.VECTOR_3, basePath .. ".ai.obstacles.obstacle(?)#size", "Obstacle box size as x y z vector, required if node is not a rigid body")
54 schema:register(XMLValueType.VECTOR_3, basePath .. ".ai.obstacles.obstacle(?)#offset", "Obstacle box offset to node as x y z vector")
55 schema:register(XMLValueType.INT, basePath .. ".ai.obstacles.obstacle(?).animatedObject#index", "Index of corresponding animated object in xml", nil, true)
56 schema:register(XMLValueType.FLOAT, basePath .. ".ai.obstacles.obstacle(?).animatedObject#startTime", "Normalized start time to activate obstacle", nil, true)
57 schema:register(XMLValueType.FLOAT, basePath .. ".ai.obstacles.obstacle(?).animatedObject#endTime", "Normalized end time to deactivate obstacle", nil, true)
58 schema:setXMLSpecializationType()
59end

setObstacleActive

Description
Definition
setObstacleActive()
Code
292function PlaceableAI:setObstacleActive(obstacle, active)
293 if active then
294 local sx, sy, sz = obstacle.size[1],obstacle.size[2],obstacle.size[3]
295 local ox, oy, oz = obstacle.offset[1],obstacle.offset[2],obstacle.offset[3]
296 addVehicleNavigationPhysicsObstacle(g_currentMission.aiSystem.navigationMap, obstacle.node, ox,oy,oz, sx, sy, sz, 0)
297 setVehicleNavigationPhysicsObstacleIsPassable(g_currentMission.aiSystem.navigationMap, obstacle.node, false)
298 else
299 removeVehicleNavigationPhysicsObstacle(g_currentMission.aiSystem.navigationMap, obstacle.node)
300 end
301 obstacle.isActive = active
302end

updateAIUpdateAreas

Description
Definition
updateAIUpdateAreas()
Code
306function PlaceableAI:updateAIUpdateAreas()
307 if self.isServer then
308 local spec = self.spec_ai
309 for _, area in pairs(spec.areas) do
310 local x, z = area.center.x, area.center.z
311 local sizeX, sizeZ = area.size.x, area.size.z
312
313 local x1, _, z1 = localToWorld(self.rootNode, x + sizeX * 0.5, 0, z + sizeZ * 0.5)
314 local x2, _, z2 = localToWorld(self.rootNode, x - sizeX * 0.5, 0, z + sizeZ * 0.5)
315 local x3, _, z3 = localToWorld(self.rootNode, x + sizeX * 0.5, 0, z - sizeZ * 0.5)
316 local x4, _, z4 = localToWorld(self.rootNode, x - sizeX * 0.5, 0, z - sizeZ * 0.5)
317
318 local minX = math.min(x1, x2, x3, x4)
319 local maxX = math.max(x1, x2, x3, x4)
320 local minZ = math.min(z1, z2, z3, z4)
321 local maxZ = math.max(z1, z2, z3, z4)
322 g_currentMission.aiSystem:setAreaDirty(minX, maxX, minZ, maxZ)
323 end
324 end
325end