116 | function AIVehicle:collectAIAgentAttachments(aiDrivableVehicle) |
117 | local spec = self.spec_aiVehicle |
118 | |
119 | if #spec.agentAttachments > 0 then |
120 | local inputAttacherJointDesc = self:getActiveInputAttacherJoint() |
121 | if inputAttacherJointDesc ~= nil then |
122 | local jointDesc = self:getAttacherVehicle():getAttacherJointDescFromObject(self) |
123 | |
124 | local usedExplicitAttachment = false |
125 | for i=1, #spec.agentAttachments do |
126 | local agentAttachment = spec.agentAttachments[i] |
127 | if agentAttachment.jointNode == inputAttacherJointDesc.node then |
128 | agentAttachment.attacherVehicleJointNode = jointDesc.jointTransform |
129 | self:registerAIAgentAttachment(aiDrivableVehicle, agentAttachment) |
130 | usedExplicitAttachment = true |
131 | end |
132 | end |
133 | |
134 | if not usedExplicitAttachment then |
135 | for i=1, #spec.agentAttachments do |
136 | local agentAttachment = spec.agentAttachments[i] |
137 | if agentAttachment.isDirectAttachment then |
138 | agentAttachment.attacherVehicleJointNode = jointDesc.jointTransform |
139 | agentAttachment.jointNodeDynamic = inputAttacherJointDesc.node |
140 | self:registerAIAgentAttachment(aiDrivableVehicle, agentAttachment) |
141 | break |
142 | end |
143 | end |
144 | end |
145 | |
146 | for i=1, #spec.agentAttachments do |
147 | local agentAttachment = spec.agentAttachments[i] |
148 | if not agentAttachment.isDirectAttachment then |
149 | self:registerAIAgentAttachment(aiDrivableVehicle, agentAttachment) |
150 | end |
151 | end |
152 | end |
153 | end |
154 | end |
276 | function AIVehicle:drawAIAgentAttachments(agentAttachments) |
277 | local spec = self.spec_aiVehicle |
278 | agentAttachments = agentAttachments or spec.agentAttachments |
279 | for i=1, #agentAttachments do |
280 | local agentAttachment = agentAttachments[i] |
281 | if agentAttachment.rotCenterNode ~= nil then |
282 | spec.debugSizeBox:setColor(0, 1, 0.25) |
283 | spec.debugSizeBox:createWithNode(agentAttachment.rotCenterNode, agentAttachment.width*0.5, agentAttachment.height*0.5, agentAttachment.length*0.5, 0, agentAttachment.height*0.5 + agentAttachment.heightOffset, agentAttachment.lengthOffset) |
284 | spec.debugSizeBox:draw() |
285 | else |
286 | spec.debugSizeBox:setColor(0, 0.15, 1) |
287 | spec.debugSizeBox:createWithNode(agentAttachment.rootNode, agentAttachment.width*0.5, agentAttachment.height*0.5, agentAttachment.length*0.5, 0, agentAttachment.height*0.5 + agentAttachment.heightOffset, agentAttachment.lengthOffset) |
288 | spec.debugSizeBox:draw() |
289 | end |
290 | |
291 | self:drawAIAgentAttachments(agentAttachment.agentAttachments) |
292 | end |
293 | end |
169 | function AIVehicle:loadAIAgentAttachmentsFromXML(xmlFile, baseKey, agentAttachments, loadSubAttachments, requiresJointNode) |
170 | xmlFile:iterate(baseKey, function(index, key) |
171 | local agentAttachment = {} |
172 | agentAttachment.jointNode = xmlFile:getValue(key .. "#jointNode", nil, self.components, self.i3dMappings) |
173 | agentAttachment.jointNodeDynamic = nil |
174 | |
175 | agentAttachment.rotCenterNode = xmlFile:getValue(key .. "#rotCenterNode", nil, self.components, self.i3dMappings) |
176 | agentAttachment.rotCenterWheelIndices = xmlFile:getValue(key .. "#rotCenterWheelIndices", nil, true) |
177 | agentAttachment.rotCenterPosition = xmlFile:getValue(key .. "#rotCenterPosition", nil, true) |
178 | |
179 | agentAttachment.width = xmlFile:getValue(key .. "#width", 3) |
180 | agentAttachment.height = xmlFile:getValue(key .. "#height", 3) |
181 | agentAttachment.heightOffset = xmlFile:getValue(key .. "#heightOffset", 0) |
182 | agentAttachment.length = xmlFile:getValue(key .. "#length", 3) |
183 | agentAttachment.lengthOffset = xmlFile:getValue(key .. "#lengthOffset", 0) |
184 | |
185 | agentAttachment.hasCollision = xmlFile:getValue(key .. "#hasCollision", true) |
186 | |
187 | agentAttachment.isDirectAttachment = false -- direct attachments are directly bound to the input attacher joint - non direct is e.g. another component with open Y rot limit |
188 | |
189 | agentAttachment.agentAttachments = {} |
190 | if loadSubAttachments ~= false then |
191 | self:loadAIAgentAttachmentsFromXML(xmlFile, key .. ".agentAttachment", agentAttachment.agentAttachments, false, true) |
192 | end |
193 | |
194 | if requiresJointNode == true then |
195 | if agentAttachment.jointNode == nil then |
196 | Logging.xmlWarning(xmlFile, "No joint node defined for ai agent sub attachable '%s'!", key) |
197 | return |
198 | end |
199 | end |
200 | |
201 | table.insert(agentAttachments, agentAttachment) |
202 | end) |
203 | |
204 | if loadSubAttachments == nil and #agentAttachments == 0 then |
205 | Logging.xmlWarning(xmlFile, "Missing ai agent attachment definition for attachable vehicle") |
206 | end |
207 | end |
297 | function AIVehicle:raiseAIEvent(eventName, implementName, ...) |
298 | local actionController = self.rootVehicle.actionController |
299 | for _, vehicle in ipairs(self.rootVehicle.childVehicles) do |
300 | if vehicle ~= self then |
301 | self:safeRaiseAIEvent(vehicle, implementName, ...) |
302 | |
303 | if actionController ~= nil then |
304 | actionController:onAIEvent(vehicle, implementName) |
305 | end |
306 | end |
307 | end |
308 | |
309 | self:safeRaiseAIEvent(self, implementName, ...) |
310 | if actionController ~= nil then |
311 | actionController:onAIEvent(self, implementName) |
312 | end |
313 | |
314 | self:safeRaiseAIEvent(self, eventName, ...) |
315 | if actionController ~= nil then |
316 | actionController:onAIEvent(self, eventName) |
317 | end |
318 | end |
34 | function AIVehicle.registerAgentAttachmentPaths(schema, basePath, includeSubAttachments) |
35 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".agentAttachment(?)#jointNode", "Custom joint node (if not defined the current attacher joint is used)") |
36 | |
37 | schema:register(XMLValueType.VECTOR_N, basePath .. ".agentAttachment(?)#rotCenterWheelIndices", "The center of these wheel indices define the steering center") |
38 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".agentAttachment(?)#rotCenterNode", "Custom node to define the steering center") |
39 | schema:register(XMLValueType.VECTOR_2, basePath .. ".agentAttachment(?)#rotCenterPosition", "Offset from root component that defines the steering center") |
40 | |
41 | schema:register(XMLValueType.FLOAT, basePath .. ".agentAttachment(?)#width", "Agent attachable width", 3) |
42 | schema:register(XMLValueType.FLOAT, basePath .. ".agentAttachment(?)#height", "Agent attachable height", 3) |
43 | schema:register(XMLValueType.FLOAT, basePath .. ".agentAttachment(?)#heightOffset", "Agent attachable height offset (only for visual debug)", 0) |
44 | schema:register(XMLValueType.FLOAT, basePath .. ".agentAttachment(?)#length", "Agent attachable length", 3) |
45 | schema:register(XMLValueType.FLOAT, basePath .. ".agentAttachment(?)#lengthOffset", "Agent attachable length offset from rot center", 0) |
46 | |
47 | schema:register(XMLValueType.BOOL, basePath .. ".agentAttachment(?)#hasCollision", "Agent attachable is doing collision checks", true) |
48 | |
49 | if includeSubAttachments then |
50 | AIVehicle.registerAgentAttachmentPaths(schema, basePath .. ".agentAttachment(?)", false) |
51 | end |
52 | end |
61 | function AIVehicle.registerFunctions(vehicleType) |
62 | SpecializationUtil.registerFunction(vehicleType, "collectAIAgentAttachments", AIVehicle.collectAIAgentAttachments) |
63 | SpecializationUtil.registerFunction(vehicleType, "registerAIAgentAttachment", AIVehicle.registerAIAgentAttachment) |
64 | SpecializationUtil.registerFunction(vehicleType, "loadAIAgentAttachmentsFromXML", AIVehicle.loadAIAgentAttachmentsFromXML) |
65 | SpecializationUtil.registerFunction(vehicleType, "validateAIAgentAttachments", AIVehicle.validateAIAgentAttachments) |
66 | SpecializationUtil.registerFunction(vehicleType, "drawAIAgentAttachments", AIVehicle.drawAIAgentAttachments) |
67 | |
68 | SpecializationUtil.registerFunction(vehicleType, "raiseAIEvent", AIVehicle.raiseAIEvent) |
69 | SpecializationUtil.registerFunction(vehicleType, "safeRaiseAIEvent", AIVehicle.safeRaiseAIEvent) |
70 | SpecializationUtil.registerFunction(vehicleType, "getIsAIReadyToDrive", AIVehicle.getIsAIReadyToDrive) |
71 | SpecializationUtil.registerFunction(vehicleType, "getIsAIPreparingToDrive", AIVehicle.getIsAIPreparingToDrive) |
72 | end |
211 | function AIVehicle:validateAIAgentAttachments(agentAttachments, inputAttacherJoints) |
212 | for i=1, #agentAttachments do |
213 | local agentAttachment = agentAttachments[i] |
214 | |
215 | for j=1, #inputAttacherJoints do |
216 | if agentAttachment.jointNode == nil or agentAttachment.jointNode == inputAttacherJoints[j].node then |
217 | agentAttachment.isDirectAttachment = true |
218 | end |
219 | end |
220 | |
221 | if agentAttachment.rotCenterNode == nil then |
222 | if agentAttachment.rotCenterPosition ~= nil and #agentAttachment.rotCenterPosition == 2 then |
223 | local rotCenterNode = createTransformGroup("aiAgentAttachmentRotCenter"..i) |
224 | link(self.components[1].node, rotCenterNode) |
225 | setTranslation(rotCenterNode, agentAttachment.rotCenterPosition[1], 0, agentAttachment.rotCenterPosition[2]) |
226 | agentAttachment.rotCenterNode = rotCenterNode |
227 | elseif agentAttachment.rotCenterWheelIndices ~= nil and #agentAttachment.rotCenterWheelIndices > 0 then |
228 | if self.getWheels ~= nil then |
229 | local wheels = self:getWheels() |
230 | local x, y, z = 0, 0, 0 |
231 | local dirX, dirY, dirZ = 0, 0, 0 |
232 | local numWheels = 0 |
233 | local component = nil |
234 | for j=1, #agentAttachment.rotCenterWheelIndices do |
235 | local wheelIndex = agentAttachment.rotCenterWheelIndices[j] |
236 | local wheel = wheels[wheelIndex] |
237 | if wheel ~= nil then |
238 | component = component or wheel.node |
239 | local wx, wy, wz = localToLocal(wheel.repr, component, 0, -wheel.radius, 0) |
240 | local dx, dy, dz = localDirectionToLocal(wheel.driveNode, component, 0, 0, 1) |
241 | x, y, z = x+wx, y+wy, z+wz |
242 | dirX, dirY, dirZ = dirX+dx, dirY+dy, dirZ+dz |
243 | numWheels = numWheels + 1 |
244 | else |
245 | Logging.xmlWarning(self.xmlFile, "Unknown wheel index '%d' ground in ai agent attachment entry 'vehicle.ai.agentAttachment(%d)'!", wheelIndex, i-1) |
246 | end |
247 | end |
248 | |
249 | if numWheels > 0 then |
250 | x, y, z = x/numWheels, y/numWheels, z/numWheels |
251 | dirX, dirY, dirZ = dirX/numWheels, dirY/numWheels, dirZ/numWheels |
252 | end |
253 | |
254 | local rotCenterNode = createTransformGroup("aiAgentAttachmentRotCenter"..i) |
255 | link(component, rotCenterNode) |
256 | setTranslation(rotCenterNode, x, y, z) |
257 | agentAttachment.rotCenterNode = rotCenterNode |
258 | |
259 | if numWheels > 0 and MathUtil.vector3Length(dirX, dirY, dirZ) > 0 then |
260 | setDirection(rotCenterNode, dirX, dirY, dirZ, 0, 1, 0) |
261 | end |
262 | end |
263 | end |
264 | end |
265 | |
266 | if agentAttachment.rotCenterNode == nil then |
267 | agentAttachment.rootNode = self.rootNode |
268 | end |
269 | |
270 | self:validateAIAgentAttachments(agentAttachment.agentAttachments, inputAttacherJoints) |
271 | end |
272 | end |