274 | function AttacherJoints:updateTick(dt) |
275 | local forceUpdate = false; |
276 | for _, implement in pairs(self.attachedImplements) do |
277 | if implement.object ~= nil then |
278 | if implement.attachingIsInProgress then |
279 | forceUpdate = true; |
280 | end |
281 | end |
282 | end |
283 | |
284 | if self:getIsActive() or forceUpdate then |
285 | local playHydraulicSound = false; |
286 | |
287 | for _, implement in pairs(self.attachedImplements) do |
288 | if implement.object ~= nil then |
289 | local jointDesc = self.attacherJoints[implement.jointDescIndex]; |
290 | |
291 | if not implement.object.isHardAttached then |
292 | if self.isServer then |
293 | if implement.attachingIsInProgress then |
294 | local done = true; |
295 | for i=1,3 do |
296 | local lastRotLimit = implement.attachingRotLimit[i]; |
297 | local lastTransLimit = implement.attachingTransLimit[i]; |
298 | implement.attachingRotLimit[i] = math.max(0, implement.attachingRotLimit[i] - implement.attachingRotLimitSpeed[i] * dt); |
299 | implement.attachingTransLimit[i] = math.max(0, implement.attachingTransLimit[i] - implement.attachingTransLimitSpeed[i] * dt); |
300 | if (implement.attachingRotLimit[i] > 0 or implement.attachingTransLimit[i] > 0) or |
301 | (lastRotLimit > 0 or lastTransLimit > 0) |
302 | then |
303 | done = false; |
304 | end |
305 | end |
306 | implement.attachingIsInProgress = not done; |
307 | |
308 | if done and implement.object.attacherJoint.hardAttach and self:getIsHardAttachAllowed(implement.jointDescIndex) then |
309 | self:hardAttachImplement(implement) |
310 | end |
311 | end |
312 | end |
313 | if not implement.attachingIsInProgress then |
314 | local jointFrameInvalid = false; |
315 | if jointDesc.allowsLowering then |
316 | local moveAlpha = Utils.getMovedLimitedValue(jointDesc.moveAlpha, jointDesc.lowerAlpha, jointDesc.upperAlpha, jointDesc.moveTime, dt, not jointDesc.moveDown); |
317 | if moveAlpha ~= jointDesc.moveAlpha then |
318 | playHydraulicSound = true; |
319 | jointDesc.moveAlpha = moveAlpha; |
320 | jointDesc.moveLimitAlpha = 1- (moveAlpha-jointDesc.lowerAlpha) / (jointDesc.upperAlpha-jointDesc.lowerAlpha); |
321 | jointFrameInvalid = true; |
322 | if jointDesc.rotationNode ~= nil then |
323 | setRotation(jointDesc.rotationNode, Utils.vector3ArrayLerp(jointDesc.upperRotation, jointDesc.lowerRotation, jointDesc.moveAlpha)); |
324 | end |
325 | if jointDesc.rotationNode2 ~= nil then |
326 | setRotation(jointDesc.rotationNode2, Utils.vector3ArrayLerp(jointDesc.upperRotation2, jointDesc.lowerRotation2, jointDesc.moveAlpha)); |
327 | end |
328 | self:updateAttacherJointRotation(jointDesc, implement.object); |
329 | end |
330 | end |
331 | |
332 | jointFrameInvalid = jointFrameInvalid or self:validateAttacherJoint(implement, jointDesc, dt); |
333 | jointFrameInvalid = jointFrameInvalid or jointDesc.jointFrameInvalid; |
334 | if jointFrameInvalid then |
335 | jointDesc.jointFrameInvalid = false; |
336 | if self.isServer then |
337 | setJointFrame(jointDesc.jointIndex, 0, jointDesc.jointTransform); |
338 | end |
339 | end |
340 | end |
341 | if self.isServer then |
342 | local force = implement.attachingIsInProgress; |
343 | if force or (jointDesc.allowsLowering and jointDesc.allowsJointLimitMovement) then |
344 | if force or implement.object.attacherJoint.allowsJointRotLimitMovement then |
345 | for i=1,3 do |
346 | local newRotLimit = Utils.lerp( math.max(implement.attachingRotLimit[i], implement.upperRotLimit[i]), |
347 | math.max(implement.attachingRotLimit[i], implement.lowerRotLimit[i]), jointDesc.moveLimitAlpha); |
348 | if force or math.abs(newRotLimit - implement.jointRotLimit[i]) > 0.0005 then |
349 | local rotLimitDown = -newRotLimit; |
350 | local rotLimitUp = newRotLimit; |
351 | if i == 3 then |
352 | if jointDesc.lockDownRotLimit then |
353 | rotLimitDown = math.min(-implement.attachingRotLimit[i], 0); |
354 | end |
355 | if jointDesc.lockUpRotLimit then |
356 | rotLimitUp = math.max(implement.attachingRotLimit[i], 0); |
357 | end |
358 | end |
359 | setJointRotationLimit(jointDesc.jointIndex, i-1, true, rotLimitDown, rotLimitUp); |
360 | implement.jointRotLimit[i] = newRotLimit; |
361 | end |
362 | end |
363 | end |
364 | |
365 | if force or implement.object.attacherJoint.allowsJointTransLimitMovement then |
366 | for i=1,3 do |
367 | local newTransLimit = Utils.lerp( math.max(implement.attachingTransLimit[i], implement.upperTransLimit[i]), |
368 | math.max(implement.attachingTransLimit[i], implement.lowerTransLimit[i]), jointDesc.moveLimitAlpha); |
369 | |
370 | if force or math.abs(newTransLimit - implement.jointTransLimit[i]) > 0.0005 then |
371 | local transLimitDown = -newTransLimit; |
372 | local transLimitUp = newTransLimit |
373 | if i == 2 then |
374 | if jointDesc.lockDownTransLimit then |
375 | transLimitDown = math.min(-implement.attachingTransLimit[i], 0); |
376 | end |
377 | if jointDesc.lockUpTransLimit then |
378 | transLimitUp = math.max(implement.attachingTransLimit[i], 0); |
379 | end |
380 | end |
381 | |
382 | setJointTranslationLimit(jointDesc.jointIndex, i-1, true, transLimitDown, transLimitUp); |
383 | implement.jointTransLimit[i] = newTransLimit; |
384 | end |
385 | end |
386 | end |
387 | end |
388 | end |
389 | end |
390 | end |
391 | end |
392 | |
393 | if self:getIsActiveForSound() and self.sampleHydraulic ~= nil and self.sampleHydraulic.sample ~= nil then |
394 | if playHydraulicSound then |
395 | if not self.sampleHydraulic.isPlaying then |
396 | SoundUtil.playSample(self.sampleHydraulic, 0, 0, nil); |
397 | end |
398 | elseif self.sampleHydraulic.isPlaying then |
399 | SoundUtil.stopSample(self.sampleHydraulic, true); |
400 | end |
401 | end |
402 | end |
403 | end |
414 | function AttacherJoints:updateAttacherJointGraphics(superFunc, implement, dt) |
415 | if superFunc ~= nil then |
416 | superFunc(self, implement, dt); |
417 | end |
418 | |
419 | if implement.object ~= nil then |
420 | local jointDesc = self.attacherJoints[implement.jointDescIndex]; |
421 | local attacherJoint = implement.object.attacherJoint; |
422 | if jointDesc.topArm ~= nil and attacherJoint.topReferenceNode ~= nil then |
423 | local ax, ay, az = getWorldTranslation(jointDesc.topArm.rotationNode); |
424 | local bx, by, bz = getWorldTranslation(attacherJoint.topReferenceNode); |
425 | |
426 | local x, y, z = worldDirectionToLocal(getParent(jointDesc.topArm.rotationNode), bx-ax, by-ay, bz-az); |
427 | local distance = Utils.vector3Length(x,y,z); |
428 | |
429 | local _, upY, upZ = 0,1,0; |
430 | if math.abs(y) > 0.99*distance then |
431 | -- direction and up is parallel |
432 | upY = 0; |
433 | if y > 0 then |
434 | upZ = 1; |
435 | else |
436 | upZ = -1; |
437 | end |
438 | end |
439 | |
440 | -- different approach I) rotate actual direction of topArm by 90degree around x-axis |
441 | local alpha = math.rad(-90); |
442 | -- check if rotationNode is at back of tractor => inverted rotation direction, could be dismissed by rotating TG in i3d |
443 | local px,py,pz = getWorldTranslation(jointDesc.topArm.rotationNode); |
444 | local _,_,lz = worldToLocal(self.components[1].node, px,py,pz); |
445 | if lz < 0 then |
446 | alpha = math.rad(90); |
447 | end |
448 | |
449 | local dx, dy, dz = localDirectionToWorld(jointDesc.topArm.rotationNode, 0,0,1); |
450 | dx, dy, dz = worldDirectionToLocal(getParent(jointDesc.topArm.rotationNode), dx, dy, dz); |
451 | local upX = dx; |
452 | local upY = math.cos(alpha)*dy - math.sin(alpha)*dz; |
453 | local upZ = math.sin(alpha)*dy + math.cos(alpha)*dz; |
454 | |
455 | setDirection(jointDesc.topArm.rotationNode, x*jointDesc.topArm.zScale, y*jointDesc.topArm.zScale, z*jointDesc.topArm.zScale, upX, upY, upZ); |
456 | if jointDesc.topArm.translationNode ~= nil and not implement.attachingIsInProgress then |
457 | local translation = (distance-jointDesc.topArm.referenceDistance) |
458 | setTranslation(jointDesc.topArm.translationNode, 0, 0, translation*jointDesc.topArm.zScale); |
459 | if jointDesc.topArm.scaleNode ~= nil then |
460 | setScale(jointDesc.topArm.scaleNode, 1, 1, math.max((translation+jointDesc.topArm.scaleReferenceDistance)/jointDesc.topArm.scaleReferenceDistance, 0)); |
461 | end |
462 | end |
463 | end |
464 | if jointDesc.bottomArm ~= nil then |
465 | local ax, ay, az = getWorldTranslation(jointDesc.bottomArm.rotationNode); |
466 | local bx, by, bz = getWorldTranslation(attacherJoint.node); |
467 | |
468 | local x, y, z = worldDirectionToLocal(getParent(jointDesc.bottomArm.rotationNode), bx-ax, by-ay, bz-az); |
469 | local distance = Utils.vector3Length(x,y,z); |
470 | local upX, upY, upZ = 0,1,0; |
471 | if math.abs(y) > 0.99*distance then |
472 | -- direction and up is parallel |
473 | upY = 0; |
474 | if y > 0 then |
475 | upZ = 1; |
476 | else |
477 | upZ = -1; |
478 | end |
479 | end |
480 | local dirX = 0 |
481 | if not jointDesc.bottomArm.lockDirection then |
482 | dirX = x*jointDesc.bottomArm.zScale |
483 | end |
484 | setDirection(jointDesc.bottomArm.rotationNode, dirX, y*jointDesc.bottomArm.zScale, z*jointDesc.bottomArm.zScale, upX, upY, upZ); |
485 | if jointDesc.bottomArm.translationNode ~= nil and not implement.attachingIsInProgress then |
486 | setTranslation(jointDesc.bottomArm.translationNode, 0, 0, (distance-jointDesc.bottomArm.referenceDistance)*jointDesc.bottomArm.zScale); |
487 | end |
488 | if self.setMovingToolDirty ~= nil then |
489 | self:setMovingToolDirty(jointDesc.bottomArm.rotationNode); |
490 | end |
491 | |
492 | if attacherJoint.needsToolbar and jointDesc.bottomArm.toolbar ~= nil then |
493 | local parent = getParent(jointDesc.bottomArm.toolbar); |
494 | |
495 | local _, yDir, zDir = localDirectionToLocal(attacherJoint.node, jointDesc.rootNode, 1, 0, 0); |
496 | local xDir, yDir, zDir = localDirectionToLocal(jointDesc.rootNode, parent, 0, yDir, zDir); |
497 | |
498 | local _, yUp, zUp = localDirectionToLocal(attacherJoint.node, jointDesc.rootNode, 0, 1, 0); |
499 | local xUp, yUp, zUp = localDirectionToLocal(jointDesc.rootNode, parent, 0, yUp, zUp); |
500 | |
501 | setDirection(jointDesc.bottomArm.toolbar, xDir, yDir, zDir, xUp, yUp, zUp); |
502 | end |
503 | end |
504 | end |
505 | |
506 | self:updatePowerTakeoff(implement, dt, "pto"); |
507 | self:updatePowerTakeoff(implement, dt, "pto2"); |
508 | end |
826 | function AttacherJoints:createAttachmentJoint(superFunc, implement, noSmoothAttach) |
827 | if superFunc ~= nil then |
828 | if not superFunc(self, implement) then |
829 | return false; |
830 | end |
831 | end |
832 | |
833 | local jointDesc = self.attacherJoints[implement.jointDescIndex]; |
834 | if self.isServer then |
835 | local xNew = jointDesc.jointOrigTrans[1] + jointDesc.jointPositionOffset[1]; |
836 | local yNew = jointDesc.jointOrigTrans[2] + jointDesc.jointPositionOffset[2]; |
837 | local zNew = jointDesc.jointOrigTrans[3] + jointDesc.jointPositionOffset[3]; |
838 | |
839 | -- transform offset position to world coord and to jointTransform coord to get position offset dependend on angle and position |
840 | local x,y,z = localToWorld(getParent(jointDesc.jointTransform), xNew, yNew, zNew); |
841 | local x1,y1,z1 = worldToLocal(jointDesc.jointTransform, x,y,z); |
842 | |
843 | -- move jointTransform to offset pos |
844 | setTranslation(jointDesc.jointTransform, xNew, yNew, zNew); |
845 | |
846 | -- transform it to implement position and angle |
847 | x,y,z = localToWorld(implement.object.attacherJoint.node,x1,y1,z1); |
848 | local x2,y2,z2 = worldToLocal(getParent(implement.object.attacherJoint.node), x,y,z); |
849 | setTranslation(implement.object.attacherJoint.node, x2,y2, z2); |
850 | |
851 | |
852 | local constr = JointConstructor:new(); |
853 | constr:setActors(jointDesc.rootNode, implement.object.attacherJoint.rootNode); |
854 | constr:setJointTransforms(jointDesc.jointTransform, implement.object.attacherJoint.node); |
855 | --constr:setBreakable(20, 10); |
856 | |
857 | implement.jointRotLimit = {}; |
858 | implement.jointTransLimit = {}; |
859 | |
860 | implement.lowerRotLimit = {}; |
861 | implement.lowerTransLimit = {}; |
862 | |
863 | implement.upperRotLimit = {}; |
864 | implement.upperTransLimit = {}; |
865 | |
866 | if noSmoothAttach == nil or not noSmoothAttach then |
867 | local dx,dy,dz = localToLocal(implement.object.attacherJoint.node, jointDesc.jointTransform, 0,0,0); |
868 | local _,y,z = localDirectionToLocal(implement.object.attacherJoint.node, jointDesc.jointTransform, 0,1,0); |
869 | local rX = math.atan2(z,y); |
870 | local x,_,z = localDirectionToLocal(implement.object.attacherJoint.node, jointDesc.jointTransform, 0,0,1); |
871 | local rY = math.atan2(x,z); |
872 | local x,y,_ = localDirectionToLocal(implement.object.attacherJoint.node, jointDesc.jointTransform, 1,0,0); |
873 | local rZ = math.atan2(y,x); |
874 | implement.attachingTransLimit = { math.abs(dx), math.abs(dy), math.abs(dz) }; |
875 | implement.attachingRotLimit = { math.abs(rX), math.abs(rY), math.abs(rZ) }; |
876 | implement.attachingTransLimitSpeed = {}; |
877 | implement.attachingRotLimitSpeed = {}; |
878 | for i=1,3 do |
879 | implement.attachingTransLimitSpeed[i] = implement.attachingTransLimit[i] / 500; |
880 | implement.attachingRotLimitSpeed[i] = implement.attachingRotLimit[i] / 500; |
881 | end |
882 | implement.attachingIsInProgress = true; |
883 | else |
884 | implement.attachingTransLimit = { 0,0,0 }; |
885 | implement.attachingRotLimit = { 0,0,0 }; |
886 | end |
887 | |
888 | for i=1, 3 do |
889 | local lowerRotLimit = jointDesc.lowerRotLimit[i]*implement.object.attacherJoint.lowerRotLimitScale[i]; |
890 | local upperRotLimit = jointDesc.upperRotLimit[i]*implement.object.attacherJoint.upperRotLimitScale[i]; |
891 | if implement.object.attacherJoint.fixedRotation then |
892 | lowerRotLimit = 0; |
893 | upperRotLimit = 0; |
894 | end |
895 | |
896 | local upperTransLimit = jointDesc.lowerTransLimit[i]*implement.object.attacherJoint.lowerTransLimitScale[i]; |
897 | local lowerTransLimit = jointDesc.upperTransLimit[i]*implement.object.attacherJoint.upperTransLimitScale[i]; |
898 | implement.lowerRotLimit[i] = lowerRotLimit; |
899 | implement.upperRotLimit[i] = upperRotLimit; |
900 | |
901 | implement.lowerTransLimit[i] = upperTransLimit; |
902 | implement.upperTransLimit[i] = lowerTransLimit; |
903 | |
904 | if not jointDesc.allowsLowering then |
905 | implement.upperRotLimit[i] = lowerRotLimit; |
906 | implement.upperTransLimit[i] = upperTransLimit; |
907 | end |
908 | |
909 | local rotLimit = lowerRotLimit; |
910 | local transLimit = upperTransLimit; |
911 | if jointDesc.allowsLowering and jointDesc.allowsJointLimitMovement then |
912 | if implement.object.attacherJoint.allowsJointRotLimitMovement then |
913 | rotLimit = Utils.lerp(upperRotLimit, lowerRotLimit, jointDesc.moveAlpha); |
914 | end |
915 | if implement.object.attacherJoint.allowsJointTransLimitMovement then |
916 | transLimit = Utils.lerp(lowerTransLimit, upperTransLimit, jointDesc.moveAlpha); |
917 | end |
918 | end |
919 | |
920 | local limitRot = rotLimit; |
921 | local limitTrans = transLimit; |
922 | if noSmoothAttach == nil or not noSmoothAttach then |
923 | limitRot = math.max(rotLimit, implement.attachingRotLimit[i]) |
924 | limitTrans = math.max(transLimit, implement.attachingTransLimit[i]); |
925 | end |
926 | |
927 | constr:setRotationLimit(i-1, -limitRot, limitRot); |
928 | implement.jointRotLimit[i] = limitRot; |
929 | constr:setTranslationLimit(i-1, true, -limitTrans, limitTrans); |
930 | implement.jointTransLimit[i] = limitTrans; |
931 | end |
932 | |
933 | if jointDesc.enableCollision then |
934 | constr:setEnableCollision(true); |
935 | else |
936 | for _, component in pairs(self.components) do |
937 | if component.node ~= jointDesc.rootNodeBackup and not component.collideWithAttachables then |
938 | setPairCollision(component.node, implement.object.attacherJoint.rootNode, false); |
939 | end |
940 | end |
941 | end |
942 | |
943 | local springX = math.max(jointDesc.rotLimitSpring[1], implement.object.attacherJoint.rotLimitSpring[1]); |
944 | local springY = math.max(jointDesc.rotLimitSpring[2], implement.object.attacherJoint.rotLimitSpring[2]); |
945 | local springZ = math.max(jointDesc.rotLimitSpring[3], implement.object.attacherJoint.rotLimitSpring[3]); |
946 | local dampingX = math.max(jointDesc.rotLimitDamping[1], implement.object.attacherJoint.rotLimitDamping[1]); |
947 | local dampingY = math.max(jointDesc.rotLimitDamping[2], implement.object.attacherJoint.rotLimitDamping[2]); |
948 | local dampingZ = math.max(jointDesc.rotLimitDamping[3], implement.object.attacherJoint.rotLimitDamping[3]); |
949 | local forceLimitX = Utils.getMaxJointForceLimit(jointDesc.rotLimitForceLimit[1], implement.object.attacherJoint.rotLimitForceLimit[1]); |
950 | local forceLimitY = Utils.getMaxJointForceLimit(jointDesc.rotLimitForceLimit[2], implement.object.attacherJoint.rotLimitForceLimit[2]); |
951 | local forceLimitZ = Utils.getMaxJointForceLimit(jointDesc.rotLimitForceLimit[3], implement.object.attacherJoint.rotLimitForceLimit[3]); |
952 | constr:setRotationLimitSpring(springX, dampingX, springY, dampingY, springZ, dampingZ); |
953 | constr:setRotationLimitForceLimit(forceLimitX, forceLimitY, forceLimitZ); |
954 | |
955 | local springX = math.max(jointDesc.transLimitSpring[1], implement.object.attacherJoint.transLimitSpring[1]); |
956 | local springY = math.max(jointDesc.transLimitSpring[2], implement.object.attacherJoint.transLimitSpring[2]); |
957 | local springZ = math.max(jointDesc.transLimitSpring[3], implement.object.attacherJoint.transLimitSpring[3]); |
958 | local dampingX = math.max(jointDesc.transLimitDamping[1], implement.object.attacherJoint.transLimitDamping[1]); |
959 | local dampingY = math.max(jointDesc.transLimitDamping[2], implement.object.attacherJoint.transLimitDamping[2]); |
960 | local dampingZ = math.max(jointDesc.transLimitDamping[3], implement.object.attacherJoint.transLimitDamping[3]); |
961 | local forceLimitX = Utils.getMaxJointForceLimit(jointDesc.transLimitForceLimit[1], implement.object.attacherJoint.transLimitForceLimit[1]); |
962 | local forceLimitY = Utils.getMaxJointForceLimit(jointDesc.transLimitForceLimit[2], implement.object.attacherJoint.transLimitForceLimit[2]); |
963 | local forceLimitZ = Utils.getMaxJointForceLimit(jointDesc.transLimitForceLimit[3], implement.object.attacherJoint.transLimitForceLimit[3]); |
964 | constr:setTranslationLimitSpring(springX, dampingX, springY, dampingY, springZ, dampingZ); |
965 | constr:setTranslationLimitForceLimit(forceLimitX, forceLimitY, forceLimitZ); |
966 | |
967 | jointDesc.jointIndex = constr:finalize(); |
968 | |
969 | -- restore implement attacher joint position (to ensure correct bottom arm alignment) |
970 | setTranslation(implement.object.attacherJoint.node, unpack(implement.object.attacherJoint.jointOrigTrans)); |
971 | else |
972 | jointDesc.jointIndex = -1; |
973 | end |
974 | end |
998 | function AttacherJoints:hardAttachImplement(superFunc, implement) |
999 | if superFunc ~= nil then |
1000 | if not superFunc(self, implement) then |
1001 | return false; |
1002 | end |
1003 | end |
1004 | |
1005 | local implements = {} |
1006 | for i=table.getn(implement.object.attachedImplements), 1, -1 do |
1007 | local impl = implement.object.attachedImplements[i] |
1008 | local object = impl.object |
1009 | local jointDescIndex = impl.jointDescIndex; |
1010 | local jointDesc = implement.object.attacherJoints[jointDescIndex]; |
1011 | local inputJointDescIndex = object.inputAttacherJointDescIndex; |
1012 | local moveDown = jointDesc.moveDown; |
1013 | table.insert(implements, 1, {object=object, implementIndex=i, jointDescIndex=jointDescIndex, inputJointDescIndex=inputJointDescIndex, moveDown=moveDown}) |
1014 | implement.object:detachImplement(1, true); |
1015 | end |
1016 | |
1017 | local attacherJoint = self.attacherJoints[implement.jointDescIndex]; |
1018 | local implementJoint = implement.object.attacherJoint |
1019 | |
1020 | local baseVehicleComponentNode = self:getParentComponent(attacherJoint.jointTransform) |
1021 | local attachedVehicleComponentNode = implement.object:getParentComponent(implement.object.attacherJoint.node) |
1022 | |
1023 | -- remove all components from physics |
1024 | local currentVehicle = self |
1025 | while currentVehicle ~= nil do |
1026 | currentVehicle:removeFromPhysics() |
1027 | currentVehicle = currentVehicle.attacherVehicle |
1028 | end |
1029 | implement.object:removeFromPhysics() |
1030 | |
1031 | -- set valid baseVehicle compound |
1032 | if self.attacherVehicle == nil then |
1033 | setIsCompound(baseVehicleComponentNode, true) |
1034 | end |
1035 | -- set attachedVehicle to compound child |
1036 | setIsCompoundChild(attachedVehicleComponentNode, true) |
1037 | |
1038 | -- set direction and local position |
1039 | local dirX, dirY, dirZ = localDirectionToLocal(attachedVehicleComponentNode, implementJoint.node, 0, 0, 1) |
1040 | local upX, upY, upZ = localDirectionToLocal(attachedVehicleComponentNode, implementJoint.node, 0, 1, 0) |
1041 | setDirection(attachedVehicleComponentNode, dirX, dirY, dirZ, upX, upY, upZ) |
1042 | local x,y,z = localToLocal(attachedVehicleComponentNode, implementJoint.node, 0, 0, 0) |
1043 | setTranslation(attachedVehicleComponentNode, x, y, z) |
1044 | link(attacherJoint.jointTransform, attachedVehicleComponentNode) |
1045 | |
1046 | -- link visual and set to correct position |
1047 | if implementJoint.visualNode ~= nil and attacherJoint.jointTransformVisual ~= nil then |
1048 | local dirX, dirY, dirZ = localDirectionToLocal(implementJoint.visualNode, implementJoint.node, 0, 0, 1) |
1049 | local upX, upY, upZ = localDirectionToLocal(implementJoint.visualNode, implementJoint.node, 0, 1, 0) |
1050 | setDirection(implementJoint.visualNode, dirX, dirY, dirZ, upX, upY, upZ) |
1051 | local x,y,z = localToLocal(implementJoint.visualNode, implementJoint.node, 0, 0, 0) |
1052 | setTranslation(implementJoint.visualNode, x, y, z) |
1053 | link(attacherJoint.jointTransformVisual, implementJoint.visualNode) |
1054 | end |
1055 | |
1056 | implement.object.isHardAttached = true |
1057 | |
1058 | -- add to physics again |
1059 | local currentVehicle = self |
1060 | while currentVehicle ~= nil do |
1061 | currentVehicle:addToPhysics() |
1062 | currentVehicle = currentVehicle.attacherVehicle |
1063 | end |
1064 | |
1065 | -- set new joint rootNodes |
1066 | for _, attacherJoint in pairs(implement.object.attacherJoints) do |
1067 | attacherJoint.rootNode = self.rootNode |
1068 | end |
1069 | |
1070 | for _, impl in pairs(implements) do |
1071 | implement.object:attachImplement(impl.object, impl.inputJointDescIndex, impl.jointDescIndex, true, impl.implementIndex, impl.moveDown, true) |
1072 | end |
1073 | |
1074 | if self.isServer then |
1075 | self:raiseDirtyFlags(self.vehicleDirtyFlag); |
1076 | end |
1077 | |
1078 | return true |
1079 | end |
1142 | function AttacherJoints:detachImplement(superFunc, implementIndex, noEventSend) |
1143 | if superFunc ~= nil then |
1144 | if not superFunc(self, implementIndex, noEventSend) then |
1145 | return false; |
1146 | end |
1147 | end |
1148 | |
1149 | if noEventSend == nil or noEventSend == false then |
1150 | if g_server ~= nil then |
1151 | g_server:broadcastEvent(VehicleDetachEvent:new(self, self.attachedImplements[implementIndex].object), nil, nil, self); |
1152 | else |
1153 | -- Send detach request to server and return |
1154 | local implement = self.attachedImplements[implementIndex]; |
1155 | if implement.object ~= nil then |
1156 | g_client:getServerConnection():sendEvent(VehicleDetachEvent:new(self, implement.object)); |
1157 | end |
1158 | return; |
1159 | end |
1160 | end |
1161 | |
1162 | self:onDetachImplement(implementIndex); |
1163 | |
1164 | local implement = self.attachedImplements[implementIndex]; |
1165 | local jointDesc; |
1166 | if implement.object ~= nil then |
1167 | jointDesc = self.attacherJoints[implement.jointDescIndex]; |
1168 | if jointDesc.transNode ~= nil then |
1169 | setTranslation(jointDesc.transNode, unpack(jointDesc.transNodeOrgTrans)); |
1170 | end |
1171 | if not implement.object.isHardAttached then |
1172 | if self.isServer then |
1173 | if jointDesc.jointIndex ~= 0 then |
1174 | removeJoint(jointDesc.jointIndex); |
1175 | end |
1176 | end |
1177 | end |
1178 | jointDesc.jointIndex = 0; |
1179 | end |
1180 | |
1181 | ObjectChangeUtil.setObjectChanges(jointDesc.changeObjects, false, self, self.setMovingToolDirty); |
1182 | |
1183 | local rootAttacherVehicle = self:getRootAttacherVehicle(); |
1184 | local selectNewImplement = false; |
1185 | |
1186 | if self.isClient then |
1187 | if rootAttacherVehicle.selectedImplement == implement then |
1188 | selectNewImplement = true; |
1189 | rootAttacherVehicle:setSelectedImplement(nil); |
1190 | end |
1191 | end |
1192 | if implement.object ~= nil then |
1193 | local object = implement.object; |
1194 | implement.object:onDetach(self, implement.jointDescIndex); |
1195 | if implement.object.isHardAttached then |
1196 | self:hardDetachImplement(implement) |
1197 | end |
1198 | implement.object = nil; |
1199 | if self.isClient then |
1200 | if jointDesc.topArm ~= nil then |
1201 | setRotation(jointDesc.topArm.rotationNode, jointDesc.topArm.rotX, jointDesc.topArm.rotY, jointDesc.topArm.rotZ); |
1202 | if jointDesc.topArm.translationNode ~= nil then |
1203 | setTranslation(jointDesc.topArm.translationNode, 0, 0, 0); |
1204 | end |
1205 | if jointDesc.topArm.scaleNode ~= nil then |
1206 | setScale(jointDesc.topArm.scaleNode, 1, 1, 1); |
1207 | end |
1208 | if jointDesc.topArm.toggleVisibility then |
1209 | setVisibility(jointDesc.topArm.rotationNode, false); |
1210 | end |
1211 | end |
1212 | if jointDesc.bottomArm ~= nil then |
1213 | setRotation(jointDesc.bottomArm.rotationNode, jointDesc.bottomArm.rotX, jointDesc.bottomArm.rotY, jointDesc.bottomArm.rotZ); |
1214 | if jointDesc.bottomArm.translationNode ~= nil then |
1215 | setTranslation(jointDesc.bottomArm.translationNode, 0, 0, 0); |
1216 | end |
1217 | if self.setMovingToolDirty ~= nil then |
1218 | self:setMovingToolDirty(jointDesc.bottomArm.rotationNode); |
1219 | end |
1220 | if jointDesc.bottomArm.toolbar ~= nil then |
1221 | setVisibility(jointDesc.bottomArm.toolbar, false) |
1222 | end |
1223 | end |
1224 | end |
1225 | if self.isServer then |
1226 | -- restore original translation |
1227 | setTranslation(jointDesc.jointTransform, unpack(jointDesc.jointOrigTrans)); |
1228 | setTranslation(object.attacherJoint.node, unpack(object.attacherJoint.jointOrigTrans)); |
1229 | |
1230 | if jointDesc.rotationNode ~= nil then |
1231 | setRotation(jointDesc.rotationNode, jointDesc.rotX, jointDesc.rotY, jointDesc.rotZ); |
1232 | end |
1233 | end |
1234 | |
1235 | local unlinkPto = function(object, jointDesc, name) |
1236 | if jointDesc[name.."Active"] then |
1237 | local input = object[name.."Input"] |
1238 | local jointDescOutput = jointDesc[name.."Output"] |
1239 | local objectOutput = object[name.."Output"] |
1240 | |
1241 | if input.rootNode ~= nil then |
1242 | unlink(input.rootNode); |
1243 | unlink(input.attachNode); |
1244 | |
1245 | if object.removeWashableNode ~= nil then |
1246 | object:removeWashableNode(objectOutput.rootNode); |
1247 | object:removeWashableNode(objectOutput.attachNode); |
1248 | object:removeWashableNode(objectOutput.dirAndScaleNode); |
1249 | end |
1250 | else |
1251 | unlink(jointDescOutput.rootNode); |
1252 | unlink(jointDescOutput.attachNode); |
1253 | |
1254 | if object.removeWashableNode ~= nil then |
1255 | object:removeWashableNode(jointDescOutput.rootNode); |
1256 | object:removeWashableNode(jointDescOutput.attachNode); |
1257 | object:removeWashableNode(jointDescOutput.dirAndScaleNode); |
1258 | end |
1259 | end |
1260 | jointDesc[name.."Active"] = false; |
1261 | end |
1262 | end |
1263 | |
1264 | unlinkPto(object, jointDesc, "pto") |
1265 | unlinkPto(object, jointDesc, "pto2") |
1266 | |
1267 | |
1268 | object:onDetached(self, implement.jointDescIndex); |
1269 | end |
1270 | |
1271 | table.remove(self.attachedImplements, implementIndex); |
1272 | |
1273 | if self.isClient then |
1274 | if selectNewImplement then |
1275 | local newSelectedImplement = nil; |
1276 | local newIndex = math.min(implementIndex, table.getn(self.attachedImplements)); |
1277 | if newIndex == 0 then |
1278 | if self ~= rootAttacherVehicle then |
1279 | -- select self |
1280 | newSelectedImplement = self.attacherVehicle:getImplementByObject(self); |
1281 | end |
1282 | else |
1283 | -- select the implement at the new index |
1284 | newSelectedImplement = self.attachedImplements[newIndex]; |
1285 | end |
1286 | rootAttacherVehicle:setSelectedImplement(newSelectedImplement); |
1287 | end |
1288 | end |
1289 | |
1290 | self:playDetachSound(jointDesc); |
1291 | |
1292 | return true; |
1293 | end |
1751 | function AttacherJoints:loadAttacherJointFromXML(superFunc, attacherJoint, xmlFile, baseName, index) |
1752 | if superFunc ~= nil then |
1753 | if not superFunc(self, attacherJoint, xmlFile, baseName, index) then |
1754 | return false; |
1755 | end |
1756 | end |
1757 | |
1758 | local node = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. "#index")); |
1759 | if node == nil then |
1760 | return false; |
1761 | end |
1762 | |
1763 | attacherJoint.jointTransform = node; |
1764 | attacherJoint.jointOrigRot = { getRotation(attacherJoint.jointTransform) }; |
1765 | attacherJoint.jointOrigTrans = { getTranslation(attacherJoint.jointTransform) }; |
1766 | |
1767 | attacherJoint.jointTransformVisual = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName .. "#indexVisual")); |
1768 | attacherJoint.supportsHardAttach = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#supportsHardAttach"), true); |
1769 | |
1770 | local jointTypeStr = getXMLString(xmlFile, baseName.. "#jointType"); |
1771 | local jointType; |
1772 | if jointTypeStr ~= nil then |
1773 | jointType = AttacherJoints.jointTypeNameToInt[jointTypeStr]; |
1774 | if jointType == nil then |
1775 | print("Warning: invalid jointType " .. jointTypeStr); |
1776 | end |
1777 | end |
1778 | if jointType == nil then |
1779 | jointType = AttacherJoints.JOINTTYPE_IMPLEMENT; |
1780 | end |
1781 | attacherJoint.jointType = jointType; |
1782 | attacherJoint.allowsJointLimitMovement = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#allowsJointLimitMovement"), true); |
1783 | attacherJoint.allowsLowering = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#allowsLowering"), true); |
1784 | attacherJoint.isDefaultLowered = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#isDefaultLowered"), false); |
1785 | |
1786 | if jointType == AttacherJoints.JOINTTYPE_TRAILER or jointType == AttacherJoints.JOINTTYPE_TRAILERLOW then |
1787 | attacherJoint.allowsLowering = false; |
1788 | end |
1789 | |
1790 | self:loadPowerTakeoff(xmlFile, baseName, attacherJoint, "pto"); |
1791 | self:loadPowerTakeoff(xmlFile, baseName, attacherJoint, "pto2"); |
1792 | |
1793 | attacherJoint.canTurnOnImplement = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#canTurnOnImplement"), true); |
1794 | |
1795 | local rotationNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. "#rotationNode")); |
1796 | if rotationNode ~= nil then |
1797 | attacherJoint.rotationNode = rotationNode; |
1798 | if getXMLString(xmlFile, baseName.."#maxRot") ~= nil then |
1799 | print("Warning: attacherJoint attribute 'maxRot' is not supported anymore. Use 'lowerRotation' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1800 | end |
1801 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#lowerRotation")); |
1802 | attacherJoint.lowerRotation = { math.rad(Utils.getNoNil(x, 0)), math.rad(Utils.getNoNil(y, 0)), math.rad(Utils.getNoNil(z, 0)) }; |
1803 | |
1804 | if getXMLString(xmlFile, baseName.."#minRot") ~= nil then |
1805 | print("Warning: attacherJoint attribute 'minRot' is not supported anymore. Use 'upperRotation' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1806 | end |
1807 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#upperRotation")); |
1808 | local rx,ry,rz = getRotation(rotationNode); |
1809 | attacherJoint.upperRotation = { Utils.getNoNilRad(x, rx), Utils.getNoNilRad(y, ry), Utils.getNoNilRad(z, rz) }; |
1810 | |
1811 | local startRot = Utils.getRadiansFromString(getXMLString(xmlFile, baseName.."#startRotation"), 3); |
1812 | if startRot ~= nil then |
1813 | attacherJoint.rotX, attacherJoint.rotY, attacherJoint.rotZ = startRot[1],startRot[2],startRot[3]; |
1814 | else |
1815 | attacherJoint.rotX, attacherJoint.rotY, attacherJoint.rotZ = getRotation(rotationNode); |
1816 | end |
1817 | end |
1818 | local rotationNode2 = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. "#rotationNode2")); |
1819 | if rotationNode2 ~= nil then |
1820 | if getXMLString(xmlFile, baseName.."#maxRot2") ~= nil then |
1821 | print("Warning: attacherJoint attribute 'maxRot2' is not supported anymore. Use 'lowerRotation2' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1822 | end |
1823 | attacherJoint.rotationNode2 = rotationNode2; |
1824 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#lowerRotation2")); |
1825 | if x ~= nil and y ~= nil and z ~= nil then |
1826 | attacherJoint.lowerRotation2 = { math.rad(Utils.getNoNil(x, 0)), math.rad(Utils.getNoNil(y, 0)), math.rad(Utils.getNoNil(z, 0)) }; |
1827 | else |
1828 | attacherJoint.lowerRotation2 = { -attacherJoint.lowerRotation[1], -attacherJoint.lowerRotation[2], -attacherJoint.lowerRotation[3] }; |
1829 | end |
1830 | |
1831 | if getXMLString(xmlFile, baseName.."#minRot2") ~= nil then |
1832 | print("Warning: attacherJoint attribute 'minRot2' is not supported anymore. Use 'upperRotation2' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1833 | end |
1834 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#upperRotation2")); |
1835 | if x ~= nil and y ~= nil and z ~= nil then |
1836 | attacherJoint.upperRotation2 = { math.rad(Utils.getNoNil(x, 0)), math.rad(Utils.getNoNil(y, 0)), math.rad(Utils.getNoNil(z, 0)) }; |
1837 | else |
1838 | attacherJoint.upperRotation2 = { -attacherJoint.upperRotation[1], -attacherJoint.upperRotation[2], -attacherJoint.upperRotation[3] }; |
1839 | end |
1840 | end |
1841 | |
1842 | if getXMLString(xmlFile, baseName.."#maxRotDistanceToGround") ~= nil then |
1843 | print("Warning: attacherJoint attribute 'maxRotDistanceToGround' is not supported anymore. Use 'lowerDistanceToGround' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1844 | end |
1845 | -- lowerDistanceToGround is a mandatory attribute if a rotationNode is available |
1846 | if attacherJoint.rotationNode ~= nil and getXMLFloat(xmlFile, baseName.."#lowerDistanceToGround") == nil then |
1847 | print("Warning: Missing 'lowerDistanceToGround' for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1848 | end |
1849 | attacherJoint.lowerDistanceToGround = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#lowerDistanceToGround"), 0.7); |
1850 | if getXMLString(xmlFile, baseName.."#minRotDistanceToGround") ~= nil then |
1851 | print("Warning: attacherJoint attribute 'minRotDistanceToGround' is not supported anymore. Use 'upperDistanceToGround' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1852 | end |
1853 | -- upperDistanceToGround is a mandatory attribute if a rotationNode is available |
1854 | if attacherJoint.rotationNode ~= nil and getXMLFloat(xmlFile, baseName.."#upperDistanceToGround") == nil then |
1855 | print("Warning: Missing 'upperDistanceToGround' for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1856 | end |
1857 | attacherJoint.upperDistanceToGround = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#upperDistanceToGround"), 1.0); |
1858 | if getXMLString(xmlFile, baseName.."#maxRotRotationOffset") ~= nil then |
1859 | print("Warning: attacherJoint attribute 'maxRotRotationOffset' is not supported anymore. Use 'lowerRotationOffset' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1860 | end |
1861 | attacherJoint.lowerRotationOffset = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#lowerRotationOffset"), 0)); |
1862 | if getXMLString(xmlFile, baseName.."#minRotRotationOffset") ~= nil then |
1863 | print("Warning: attacherJoint attribute 'minRotRotationOffset' is not supported anymore. Use 'upperRotationOffset' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1864 | end |
1865 | attacherJoint.upperRotationOffset = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#upperRotationOffset"), 0)); |
1866 | |
1867 | attacherJoint.lockDownRotLimit = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#lockDownRotLimit"), false); |
1868 | attacherJoint.lockUpRotLimit = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#lockUpRotLimit"), false); |
1869 | -- only use translimit in +y. Set -y to 0; |
1870 | attacherJoint.lockDownTransLimit = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#lockDownTransLimit"), true); |
1871 | attacherJoint.lockUpTransLimit = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#lockUpTransLimit"), false); |
1872 | |
1873 | attacherJoint.aiAllowTurnBackward = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#aiAllowTurnBackward"), false); |
1874 | |
1875 | if getXMLString(xmlFile, baseName.."#maxRotLimit") ~= nil then |
1876 | print("Warning: attacherJoint attribute 'maxRotLimit' is not supported anymore. Use 'lowerRotLimit' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1877 | end |
1878 | if getXMLString(xmlFile, baseName.."#minRotLimit") ~= nil then |
1879 | print("Warning: attacherJoint attribute 'minRotLimit' is not supported anymore. Use 'upperRotLimit' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1880 | end |
1881 | |
1882 | local lowerRotLimitStr = "20 20 20" |
1883 | if jointType ~= AttacherJoints.JOINTTYPE_IMPLEMENT then |
1884 | lowerRotLimitStr = "0 0 0" |
1885 | end |
1886 | local lx, ly, lz = Utils.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, baseName.."#lowerRotLimit"), lowerRotLimitStr)); |
1887 | attacherJoint.lowerRotLimit = {}; |
1888 | attacherJoint.lowerRotLimit[1] = math.rad(math.abs(Utils.getNoNil(lx, 20))); |
1889 | attacherJoint.lowerRotLimit[2] = math.rad(math.abs(Utils.getNoNil(ly, 20))); |
1890 | attacherJoint.lowerRotLimit[3] = math.rad(math.abs(Utils.getNoNil(lz, 20))); |
1891 | local ux, uy, uz = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#upperRotLimit")); |
1892 | attacherJoint.upperRotLimit = {}; |
1893 | attacherJoint.upperRotLimit[1] = math.rad(math.abs(Utils.getNoNil(Utils.getNoNil(ux, lx), 20))); |
1894 | attacherJoint.upperRotLimit[2] = math.rad(math.abs(Utils.getNoNil(Utils.getNoNil(uy, ly), 20))); |
1895 | attacherJoint.upperRotLimit[3] = math.rad(math.abs(Utils.getNoNil(Utils.getNoNil(uz, lz), 20))); |
1896 | |
1897 | if getXMLString(xmlFile, baseName.."#maxTransLimit") ~= nil then |
1898 | print("Warning: attacherJoint attribute 'maxTransLimit' is not supported anymore. Use 'lowerTransLimit' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1899 | end |
1900 | if getXMLString(xmlFile, baseName.."#minTransLimit") ~= nil then |
1901 | print("Warning: attacherJoint attribute 'minTransLimit' is not supported anymore. Use 'upperTransLimit' instead for attacherJoint "..(index+1).." in "..self.configFileName.."!"); |
1902 | end |
1903 | |
1904 | local lowerTransLimitStr = "0.5 0.5 0.5" |
1905 | if jointType ~= AttacherJoints.JOINTTYPE_IMPLEMENT then |
1906 | lowerTransLimitStr = "0 0 0" |
1907 | end |
1908 | local lx, ly, lz = Utils.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, baseName.."#lowerTransLimit"), lowerTransLimitStr)); |
1909 | attacherJoint.lowerTransLimit = {}; |
1910 | attacherJoint.lowerTransLimit[1] = math.abs(Utils.getNoNil(lx, 0)); |
1911 | attacherJoint.lowerTransLimit[2] = math.abs(Utils.getNoNil(ly, 0)); |
1912 | attacherJoint.lowerTransLimit[3] = math.abs(Utils.getNoNil(lz, 0)); |
1913 | local ux, uy, uz = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#upperTransLimit")); |
1914 | attacherJoint.upperTransLimit = {}; |
1915 | attacherJoint.upperTransLimit[1] = math.abs(Utils.getNoNil(Utils.getNoNil(ux, lx), 0)); |
1916 | attacherJoint.upperTransLimit[2] = math.abs(Utils.getNoNil(Utils.getNoNil(uy, ly), 0)); |
1917 | attacherJoint.upperTransLimit[3] = math.abs(Utils.getNoNil(Utils.getNoNil(uz, lz), 0)); |
1918 | |
1919 | |
1920 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#jointPositionOffset")); |
1921 | attacherJoint.jointPositionOffset = {}; |
1922 | attacherJoint.jointPositionOffset[1] = Utils.getNoNil(x, 0); |
1923 | attacherJoint.jointPositionOffset[2] = Utils.getNoNil(y, 0); |
1924 | attacherJoint.jointPositionOffset[3] = Utils.getNoNil(z, 0); |
1925 | |
1926 | attacherJoint.transNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.."#transNode")); |
1927 | if attacherJoint.transNode ~= nil then |
1928 | attacherJoint.transNodeOrgTrans = {getTranslation(attacherJoint.transNode)}; |
1929 | attacherJoint.transNodeMinY = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#transNodeMinY"), attacherJoint.jointOrigTrans[2]); |
1930 | attacherJoint.transNodeMaxY = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#transNodeMaxY"), attacherJoint.jointOrigTrans[2]); |
1931 | _, attacherJoint.transNodeOffsetY, _ = localToLocal(attacherJoint.jointTransform, attacherJoint.transNode, 0, 0, 0) |
1932 | _, attacherJoint.transNodeMinY, _ = localToLocal(getParent(attacherJoint.transNode), self.rootNode, 0, attacherJoint.transNodeMinY, 0) |
1933 | _, attacherJoint.transNodeMaxY, _ = localToLocal(getParent(attacherJoint.transNode), self.rootNode, 0, attacherJoint.transNodeMaxY, 0) |
1934 | attacherJoint.transNodeHeight = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#transNodeHeight"), 0.1) |
1935 | end |
1936 | |
1937 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#rotLimitSpring")); |
1938 | attacherJoint.rotLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }; |
1939 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#rotLimitDamping")); |
1940 | attacherJoint.rotLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }; |
1941 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#rotLimitForceLimit")); |
1942 | attacherJoint.rotLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) }; |
1943 | |
1944 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#transLimitSpring")); |
1945 | attacherJoint.transLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }; |
1946 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#transLimitDamping")); |
1947 | attacherJoint.transLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }; |
1948 | local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.."#transLimitForceLimit")); |
1949 | attacherJoint.transLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) }; |
1950 | |
1951 | attacherJoint.moveDefaultTime = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#moveTime"), 0.5)*1000; |
1952 | attacherJoint.moveTime = attacherJoint.moveDefaultTime; |
1953 | |
1954 | attacherJoint.enableCollision = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#enableCollision"), false); |
1955 | |
1956 | local topArmFilename = getXMLString(xmlFile, baseName.. ".topArm#filename"); |
1957 | if topArmFilename ~= nil then |
1958 | local baseNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".topArm#baseNode")); |
1959 | if baseNode ~= nil then |
1960 | local i3dNode = Utils.loadSharedI3DFile(topArmFilename,self.baseDirectory, false, false, false); |
1961 | if i3dNode ~= 0 then |
1962 | local rootNode = getChildAt(i3dNode, 0); |
1963 | link(baseNode, rootNode); |
1964 | delete(i3dNode); |
1965 | setTranslation(rootNode, 0,0,0); |
1966 | local translationNode = getChildAt(rootNode, 0); |
1967 | local referenceNode = getChildAt(translationNode, 0); |
1968 | |
1969 | |
1970 | local topArm = {}; |
1971 | topArm.rotationNode = rootNode; |
1972 | topArm.rotX, topArm.rotY, topArm.rotZ = 0,0,0; |
1973 | topArm.translationNode = translationNode; |
1974 | |
1975 | local _,_,referenceDistance = getTranslation(referenceNode); |
1976 | topArm.referenceDistance = referenceDistance; |
1977 | |
1978 | topArm.zScale = 1; |
1979 | local zScale = Utils.sign(Utils.getNoNil(getXMLFloat(xmlFile, baseName.. ".topArm#zScale"), 1)); |
1980 | if zScale < 0 then |
1981 | topArm.rotY = math.pi; |
1982 | setRotation(rootNode, topArm.rotX, topArm.rotY, topArm.rotZ); |
1983 | end |
1984 | |
1985 | if getNumOfChildren(rootNode) > 1 then |
1986 | topArm.scaleNode = getChildAt(rootNode, 1); |
1987 | local scaleReferenceNode = getChildAt(topArm.scaleNode, 0); |
1988 | local _,_,scaleReferenceDistance = getTranslation(scaleReferenceNode); |
1989 | topArm.scaleReferenceDistance = scaleReferenceDistance; |
1990 | end |
1991 | |
1992 | topArm.toggleVisibility = Utils.getNoNil(getXMLBool(xmlFile, baseName.. ".topArm#toggleVisibility"), false); |
1993 | if topArm.toggleVisibility then |
1994 | setVisibility(topArm.rotationNode, false); |
1995 | end |
1996 | |
1997 | attacherJoint.topArm = topArm; |
1998 | end |
1999 | end |
2000 | else |
2001 | local rotationNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".topArm#rotationNode")); |
2002 | local translationNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".topArm#translationNode")); |
2003 | local referenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".topArm#referenceNode")); |
2004 | if rotationNode ~= nil then |
2005 | local topArm = {}; |
2006 | topArm.rotationNode = rotationNode; |
2007 | topArm.rotX, topArm.rotY, topArm.rotZ = getRotation(rotationNode); |
2008 | if translationNode ~= nil and referenceNode ~= nil then |
2009 | topArm.translationNode = translationNode; |
2010 | |
2011 | local x,y,z = getTranslation(translationNode); |
2012 | if math.abs(x) >= 0.0001 or math.abs(y) >= 0.0001 or math.abs(z) >= 0.0001 then |
2013 | print("Warning: translation of topArm of attacherJoint "..(index+1).." is not 0/0/0 in '"..self.configFileName.."'"); |
2014 | end |
2015 | local ax, ay, az = getWorldTranslation(referenceNode); |
2016 | local bx, by, bz = getWorldTranslation(translationNode); |
2017 | topArm.referenceDistance = Utils.vector3Length(ax-bx, ay-by, az-bz); |
2018 | end |
2019 | topArm.zScale = Utils.sign(Utils.getNoNil(getXMLFloat(xmlFile, baseName.. ".topArm#zScale"), 1)); |
2020 | topArm.toggleVisibility = Utils.getNoNil(getXMLBool(xmlFile, baseName.. ".topArm#toggleVisibility"), false); |
2021 | if topArm.toggleVisibility then |
2022 | setVisibility(topArm.rotationNode, false); |
2023 | end |
2024 | |
2025 | attacherJoint.topArm = topArm; |
2026 | end |
2027 | end |
2028 | |
2029 | local rotationNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".bottomArm#rotationNode")); |
2030 | local translationNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".bottomArm#translationNode")); |
2031 | local referenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".bottomArm#referenceNode")); |
2032 | if rotationNode ~= nil then |
2033 | local bottomArm = {}; |
2034 | bottomArm.rotationNode = rotationNode; |
2035 | local startRot = Utils.getRadiansFromString(getXMLString(xmlFile, baseName..".bottomArm#startRotation"), 3); |
2036 | if startRot ~= nil then |
2037 | bottomArm.rotX, bottomArm.rotY, bottomArm.rotZ = startRot[1],startRot[2],startRot[3]; |
2038 | else |
2039 | bottomArm.rotX, bottomArm.rotY, bottomArm.rotZ = getRotation(rotationNode); |
2040 | end |
2041 | if translationNode ~= nil and referenceNode ~= nil then |
2042 | bottomArm.translationNode = translationNode; |
2043 | |
2044 | local x,y,z = getTranslation(translationNode); |
2045 | if math.abs(x) >= 0.0001 or math.abs(y) >= 0.0001 or math.abs(z) >= 0.0001 then |
2046 | print("Warning: translation of bottomArm '"..getName(translationNode).."' of attacherJoint "..(index+1).." is "..math.abs(x) .. "/" .. math.abs(y) .. "/" .. math.abs(z) .. "! Should be 0/0/0! ("..self.configFileName..")"); |
2047 | end |
2048 | local ax, ay, az = getWorldTranslation(referenceNode); |
2049 | local bx, by, bz = getWorldTranslation(translationNode); |
2050 | bottomArm.referenceDistance = Utils.vector3Length(ax-bx, ay-by, az-bz); |
2051 | end |
2052 | bottomArm.zScale = Utils.sign(Utils.getNoNil(getXMLFloat(xmlFile, baseName.. ".bottomArm#zScale"), 1)); |
2053 | bottomArm.lockDirection = Utils.getNoNil(getXMLBool(xmlFile, baseName.. ".bottomArm#lockDirection"), true); |
2054 | |
2055 | if jointType == AttacherJoints.JOINTTYPE_IMPLEMENT then |
2056 | local toolbarFilename = Utils.getNoNil(getXMLString(xmlFile, baseName.. ".toolbar#filename"), "$data/shared/vehicleParts/toolbar.i3d"); |
2057 | local i3dNode = Utils.loadSharedI3DFile(toolbarFilename, self.baseDirectory, false, false, false); |
2058 | if i3dNode ~= 0 then |
2059 | local rootNode = getChildAt(i3dNode, 0); |
2060 | link(referenceNode, rootNode); |
2061 | delete(i3dNode); |
2062 | setTranslation(rootNode, 0,0,0); |
2063 | bottomArm.toolbar = rootNode |
2064 | setVisibility(rootNode, false) |
2065 | end |
2066 | end |
2067 | |
2068 | attacherJoint.bottomArm = bottomArm; |
2069 | end |
2070 | |
2071 | local sample = {} |
2072 | SoundUtil.loadSample(xmlFile, sample, baseName..".attachSound", nil, self.baseDirectory); |
2073 | if sample.sample ~= nil then |
2074 | attacherJoint.sampleAttach = sample |
2075 | end |
2076 | |
2077 | attacherJoint.steeringBarLeftNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".steeringBars#leftNode")); |
2078 | attacherJoint.steeringBarRightNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.. ".steeringBars#rightNode")); |
2079 | |
2080 | attacherJoint.changeObjects = {}; |
2081 | ObjectChangeUtil.loadObjectChangeFromXML(xmlFile, baseName, attacherJoint.changeObjects, self.components, self); |
2082 | -- ObjectChangeUtil.setObjectChanges(attacherJoint.changeObjects, false, self, self.setMovingToolDirty) |
2083 | |
2084 | attacherJoint.rootNode = Utils.getNoNil(Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.."#rootNode")), self.components[1].node); |
2085 | attacherJoint.rootNodeBackup = attacherJoint.rootNode |
2086 | attacherJoint.jointIndex = 0; |
2087 | |
2088 | local schemaKey = baseName.. ".schema" |
2089 | if hasXMLProperty(xmlFile, schemaKey) then |
2090 | local x, y = Utils.getVectorFromString(getXMLString(xmlFile, schemaKey.."#position")); |
2091 | local rotation = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, schemaKey.."#rotation"), 0)); |
2092 | local invertX = Utils.getNoNil(getXMLBool(xmlFile, schemaKey.."#invertX"), false); |
2093 | local liftedOffsetX, liftedOffsetY = Utils.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, schemaKey.."#liftedOffset"), "0 5")); |
2094 | table.insert(self.schemaOverlay.attacherJoints, {x=x,y=y, rotation=rotation,invertX=invertX,liftedOffsetX=liftedOffsetX,liftedOffsetY=liftedOffsetY}); |
2095 | else |
2096 | print("Warning: Missing schema overlay for '".. baseName .."' in '"..self.configFileName.."'") |
2097 | end |
2098 | |
2099 | return true; |
2100 | end |