LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

TensionBelts

Description
Class for vehicle which can dynamically mount objects (e.g. bales and pallets)
Functions

actionEventToggleTensionBelts

Description
Definition
actionEventToggleTensionBelts()
Code
1431function TensionBelts.actionEventToggleTensionBelts(self, actionName, inputValue, callbackState, isAnalog)
1432 local spec = self.spec_tensionBelts
1433
1434 spec.fastedAllBeltsIndex = 1
1435 spec.fastedAllBeltsState = not spec.areBeltsFasten
1436end

consoleCommandToggleTensionBeltDebugRendering

Description
Definition
consoleCommandToggleTensionBeltDebugRendering()
Code
1440function TensionBelts.consoleCommandToggleTensionBeltDebugRendering(unusedSelf)
1441 TensionBelts.debugRendering = not TensionBelts.debugRendering
1442 return "TensionBeltsDebugRendering = "..tostring(TensionBelts.debugRendering)
1443end

createTensionBelt

Description
Create tension belt
Definition
createTensionBelt(table belt, boolean isDummy, table object, boolean playSound)
Arguments
tablebeltbelt to use
booleanisDummycreate dummy belt
tableobjectobjects to fasten
booleanplaySoundplay sound (nil = true)
Code
891function TensionBelts:createTensionBelt(belt, isDummy, objects, playSound)
892 local spec = self.spec_tensionBelts
893
894 local tensionBelt = TensionBeltGeometryConstructor.new()
895
896 local beltData = spec.beltData
897 local width = spec.width or beltData.width
898
899 tensionBelt:setWidth(beltData.width)
900 tensionBelt:setMaxEdgeLength(spec.maxEdgeLength)
901 if isDummy then
902 tensionBelt:setMaterial(beltData.dummyMaterial.materialId)
903 tensionBelt:setUVscale(beltData.dummyMaterial.uvScale)
904 else
905 tensionBelt:setMaterial(beltData.material.materialId)
906 tensionBelt:setUVscale(beltData.material.uvScale)
907 end
908
909 if spec.ratchetPosition ~= nil and beltData.ratchet ~= nil then
910 tensionBelt:addAttachment(0, spec.ratchetPosition, beltData.ratchet.sizeRatio*width)
911 end
912
913 if spec.useHooks and beltData.hook ~= nil then
914 tensionBelt:addAttachment(0, 0, beltData.hook.sizeRatio*width)
915 tensionBelt:addAttachment(1, 0, (beltData.hook2 or beltData.hook).sizeRatio*width)
916 end
917
918 tensionBelt:setFixedPoints(belt.startNode, belt.endNode)
919 tensionBelt:setGeometryBias(spec.geometryBias)
920 tensionBelt:setLinkNode(spec.linkNode)
921
922 for _, pointNode in pairs(belt.intersectionNodes) do
923 local x,y,z = getWorldTranslation(pointNode)
924 local dirX, dirY, dirZ = localDirectionToWorld(pointNode, 1, 0, 0)
925 tensionBelt:addIntersectionPoint(x,y,z, dirX, dirY, dirZ)
926 end
927
928 for _, object in pairs(objects) do
929 for _, node in pairs(object.visuals) do
930 if getSplitType(node) ~= 0 then
931 -- Allow a larger range of uvs for trees
932 tensionBelt:addShape(node, -100, 100, -100, 100)
933 else
934 tensionBelt:addShape(node, 0, 1, 0, 1)
935 end
936 end
937 end
938
939 local beltShape, _, beltLength = tensionBelt:finalize()
940 if beltShape ~= 0 then
941 if isDummy then
942 belt.dummy = beltShape
943 else
944 local currentIndex = 0
945 if spec.ratchetPosition ~= nil and beltData.ratchet ~= nil then
946 if getNumOfChildren(beltShape) > currentIndex then
947 local scale = width
948 local ratched = clone(beltData.ratchet.node, false, false, false)
949 link(getChildAt(beltShape, 0), ratched)
950 setScale(ratched, scale, scale, scale)
951 currentIndex = currentIndex + 1
952 end
953 end
954 if spec.useHooks then
955 if beltData.hook ~= nil and getNumOfChildren(beltShape) > currentIndex+1 then
956 local scale = width
957 local hookStart = clone(beltData.hook.node, false, false, false)
958 link(getChildAt(beltShape, currentIndex), hookStart)
959 setScale(hookStart, scale, scale, scale)
960
961 local hook2 = beltData.hook2 or beltData.hook
962 local hookEnd = clone(hook2.node, false, false, false)
963 link(getChildAt(beltShape, currentIndex+1), hookEnd)
964 setRotation(hookEnd, 0, math.pi, 0)
965 setTranslation(hookEnd, 0, 0, hook2.sizeRatio*width)
966 setScale(hookEnd, scale, scale, scale)
967
968 setShaderParameter(beltShape, "beltClipOffsets", 0, beltData.hook.sizeRatio*width, beltLength-hook2.sizeRatio*width, beltLength, false)
969 end
970 end
971
972 belt.mesh = beltShape
973 spec.belts[beltShape] = beltShape
974 if belt.dummy ~= nil then
975 delete(belt.dummy)
976 belt.dummy = nil
977 end
978
979 if playSound ~= false and self.isClient then
980 g_soundManager:playSample(spec.samples.toggleBelt)
981 g_soundManager:playSample(spec.samples.addBelt)
982 end
983 end
984
985 return beltShape
986 end
987
988 return nil
989end

freeTensionBeltObject

Description
Definition
freeTensionBeltObject()
Code
647function TensionBelts:freeTensionBeltObject(objectId, objectsToJointTable, isDynamic, object)
648 if entityExists(objectId) then
649 local jointData = objectsToJointTable[objectId]
650 if jointData.jointIndex ~= nil then
651 if self.isServer then
652 if jointData ~= nil then
653 removeJoint(jointData.jointIndex)
654 delete(jointData.jointTransform)
655
656 if object ~= nil then
657 if object.setReducedComponentMass ~= nil then
658 object:setReducedComponentMass(false)
659 self:setMassDirty()
660 end
661 if object.setCanBeSold ~= nil then
662 object:setCanBeSold(true)
663 end
664 end
665 end
666 end
667 else
668 local parentNode
669 if jointData ~= nil then
670 parentNode = jointData.parent
671 end
672 if parentNode ~= nil and not entityExists(parentNode) then
673 -- For some reason the original parent node was deleted. Delete the attached node too
674 delete(objectId)
675 else
676 if parentNode == nil then
677 parentNode = getRootNode()
678 end
679 local x, y, z = getWorldTranslation(objectId)
680 local rx, ry, rz = getWorldRotation(objectId)
681
682 if object ~= nil and object.unmountKinematic ~= nil then
683 object:unmountKinematic()
684 else
685 -- only for split shapes on server side
686 if self.isServer then
687 link(parentNode, objectId)
688 setWorldTranslation(objectId, x, y, z)
689 setWorldRotation(objectId, rx, ry, rz)
690 setRigidBodyType(objectId, RigidBodyType.DYNAMIC)
691 end
692 end
693 end
694 end
695 end
696
697 -- remove objectId from object list
698 objectsToJointTable[objectId] = nil
699end

getAdditionalComponentMass

Description
Definition
getAdditionalComponentMass()
Code
1304function TensionBelts:getAdditionalComponentMass(superFunc, component)
1305 local additionalMass = superFunc(self, component)
1306
1307 local spec = self.spec_tensionBelts
1308 if spec.hasTensionBelts then
1309 if spec.jointComponent == component.node then
1310 for _, objectData in pairs(spec.objectsToJoint) do
1311 local object = objectData.object
1312 if object ~= nil then
1313 if object.getAllowComponentMassReduction ~= nil and object:getAllowComponentMassReduction() then
1314 additionalMass = additionalMass + math.max((object:getDefaultMass() - 0.1), 0)
1315 end
1316 end
1317 end
1318 end
1319 end
1320
1321 return additionalMass
1322end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
1256function TensionBelts:getCanBeSelected(superFunc)
1257 return true
1258end

getFillLevelInformation

Description
Definition
getFillLevelInformation()
Code
1275function TensionBelts:getFillLevelInformation(superFunc, display)
1276 superFunc(self, display)
1277
1278 local spec = self.spec_tensionBelts
1279 if spec.hasTensionBelts then
1280 for _, objectData in pairs(spec.objectsToJoint) do
1281 local object = objectData.object
1282 if object ~= nil then
1283 if object.getFillLevelInformation ~= nil then
1284 object:getFillLevelInformation(display)
1285 else
1286 if object.getFillLevel ~= nil and object.getFillType ~= nil then
1287 local fillType = object:getFillType()
1288 local fillLevel = object:getFillLevel()
1289 local capacity = fillLevel
1290 if object.getCapacity ~= nil then
1291 capacity = object:getCapacity()
1292 end
1293
1294 display:addFillLevel(fillType, fillLevel, capacity)
1295 end
1296 end
1297 end
1298 end
1299 end
1300end

getIsDynamicallyMountedNode

Description
Definition
getIsDynamicallyMountedNode()
Code
1229function TensionBelts:getIsDynamicallyMountedNode(node)
1230 local spec = self.spec_tensionBelts
1231
1232 if spec.objectsToJoint ~= nil then
1233 for object,_ in pairs(spec.objectsToJoint) do
1234 if object == node then
1235 return true
1236 end
1237 end
1238 end
1239
1240 return false
1241end

getIsFoldAllowed

Description
Definition
getIsFoldAllowed()
Code
1262function TensionBelts:getIsFoldAllowed(superFunc, direction, onAiTurnOn)
1263 local spec = self.spec_tensionBelts
1264 if not spec.allowFoldingWhileFasten then
1265 if not (direction < 0 or not spec.areBeltsFasten) then
1266 return false, spec.texts.warningFoldingTensionBelts
1267 end
1268 end
1269
1270 return superFunc(self, direction, onAiTurnOn)
1271end

getIsPlayerInTensionBeltsRange

Description
Returns if player is in tension belt range
Definition
getIsPlayerInTensionBeltsRange()
Return Values
booleaninRangeplayer is in range
tablebeltnearest belt
Code
1186function TensionBelts:getIsPlayerInTensionBeltsRange()
1187
1188 if g_currentMission.player == nil then
1189 return false, nil
1190 end
1191
1192 if not g_currentMission.accessHandler:canPlayerAccess(self) then
1193 return false, nil
1194 end
1195
1196 local spec = self.spec_tensionBelts
1197
1198 if spec.beltData ~= nil then
1199 local px, py, pz = getWorldTranslation(g_currentMission.player.rootNode)
1200 local vx, vy, vz = localToWorld(spec.interactionBaseNode, spec.interactionBasePointX, 0, spec.interactionBasePointZ)
1201 local currentBelt = nil
1202 local distance = math.huge
1203
1204 if MathUtil.vector3Length(px-vx, py-vy, pz-vz) < spec.totalInteractionRadius then
1205 if spec.tensionBelts ~= nil then
1206 for _, belt in pairs(spec.singleBelts) do
1207 local sx, _, sz = getWorldTranslation(belt.startNode)
1208 local ex, _, ez = getWorldTranslation(belt.endNode)
1209 local sDistance = MathUtil.vector2Length(px-sx, pz-sz)
1210 local eDistance = MathUtil.vector2Length(px-ex, pz-ez)
1211 if (sDistance < distance and sDistance < spec.interactionRadius) or (eDistance < distance and eDistance < spec.interactionRadius) then
1212 currentBelt = belt
1213 distance = math.min(sDistance, eDistance)
1214 end
1215 end
1216 end
1217
1218 if distance < spec.interactionRadius then
1219 return true, currentBelt
1220 end
1221 end
1222 end
1223
1224 return false, nil
1225end

getIsReadyForAutomatedTrainTravel

Description
Definition
getIsReadyForAutomatedTrainTravel()
Code
1245function TensionBelts:getIsReadyForAutomatedTrainTravel(superFunc)
1246 local spec = self.spec_tensionBelts
1247 if spec.hasTensionBelts and spec.numObjectsIntensionBeltRange > 0 then
1248 return false
1249 end
1250
1251 return superFunc(self)
1252end

getObjectsToUnmount

Description
Returns objects to unmount if given belt will be removed
Definition
getObjectsToUnmount(table belt)
Arguments
tablebeltbelt to check
Return Values
tableobjectIdsToUnmounttable with object ids to unmount
integernumObjectsnumber of objects to unmount
Code
1121function TensionBelts:getObjectsToUnmount(belt)
1122 local spec = self.spec_tensionBelts
1123
1124 local objectIdsToUnmount = {}
1125 local numObjects = 0
1126 -- copy mounted objects table
1127 for objectId, data in pairs(spec.objectsToJoint) do
1128 objectIdsToUnmount[objectId] = {objectId=objectId, object=data.object}
1129 numObjects = numObjects + 1
1130 end
1131
1132 -- remove objects mounted by other active belts
1133 for _, otherBelt in pairs(spec.singleBelts) do
1134 if otherBelt.mesh ~= nil and otherBelt ~= belt then
1135 local objectToMount,_ = self:getObjectToMount(otherBelt)
1136 for _, object in pairs(objectToMount) do
1137 -- remove objects mounted by other belts
1138 if objectIdsToUnmount[object.physics] ~= nil then
1139 objectIdsToUnmount[object.physics] = nil
1140 numObjects = numObjects - 1
1141 end
1142 end
1143 end
1144 end
1145
1146 return objectIdsToUnmount, numObjects
1147end

getObjectToMount

Description
Returns objects in belt range
Definition
getObjectToMount(table belt)
Arguments
tablebeltbelt to check
Return Values
tableobjectsInTensionBeltRangeobject in belt range
integernumObjectsIntensionBeltRangenumber of objects in belt range
Code
1020function TensionBelts:getObjectToMount(belt)
1021 local spec = self.spec_tensionBelts
1022
1023 local markerStart = spec.startNode
1024 local markerEnd = spec.endNode
1025 local offsetLeft = nil
1026 local offsetRight = nil
1027 local offset = nil
1028 local height = nil
1029 if belt ~= nil then
1030 markerStart = belt.startNode
1031 markerEnd = belt.endNode
1032
1033 offsetLeft = belt.offsetLeft
1034 offsetRight = belt.offsetRight
1035 offset = belt.offset
1036 height = belt.height
1037 if offsetLeft == nil then
1038 if spec.sortedBelts[belt.id-1] ~= nil and spec.sortedBelts[belt.id-1].mesh ~= nil then
1039 local x,_,_ = localToLocal(markerStart, spec.sortedBelts[belt.id-1].startNode, 0, 0, 0)
1040 offsetLeft = math.abs(x)
1041 end
1042 end
1043 if offsetRight == nil then
1044 if spec.sortedBelts[belt.id+1] ~= nil and spec.sortedBelts[belt.id+1].mesh ~= nil then
1045 local x,_,_ = localToLocal(markerStart, spec.sortedBelts[belt.id+1].startNode, 0, 0, 0)
1046 offsetRight = math.abs(x)
1047 end
1048 end
1049
1050 end
1051
1052 if offsetLeft == nil then
1053 offsetLeft = spec.defaultOffsetSide
1054 end
1055 if offsetRight == nil then
1056 offsetRight = spec.defaultOffsetSide
1057 end
1058 if offset == nil then
1059 offset = spec.defaultOffset
1060 end
1061 if height == nil then
1062 height = spec.defaultHeight
1063 end
1064
1065 local sizeX = (offsetLeft+offsetRight) * 0.5
1066 local sizeY = height * 0.5
1067 local _, _, width = localToLocal(markerEnd, markerStart, 0, 0, 0)
1068 local sizeZ = width*0.5 - 2*offset
1069
1070 local centerX = (offsetLeft-offsetRight)*0.5
1071 local centerY = height*0.5
1072 local centerZ = width*0.5
1073 local x,y,z = localToWorld(markerStart, centerX, centerY, centerZ)
1074
1075 if TensionBelts.debugRendering then
1076 local box = {}
1077 box.points = {}
1078 local colorR = math.random(0, 1)
1079 local colorG = math.random(0, 1)
1080 local colorB = math.random(0, 1)
1081 box.color = {colorR,colorG,colorB}
1082
1083 local blx, bly, blz = localToWorld(markerStart, centerX-sizeX, centerY-sizeY, centerZ-sizeZ)
1084 local brx, bry, brz = localToWorld(markerStart, centerX+sizeX, centerY-sizeY, centerZ-sizeZ)
1085 local flx, fly, flz = localToWorld(markerStart, centerX-sizeX, centerY-sizeY, centerZ+sizeZ)
1086 local frx, fry, frz = localToWorld(markerStart, centerX+sizeX, centerY-sizeY, centerZ+sizeZ)
1087
1088 local tblx, tbly, tblz = localToWorld(markerStart, centerX-sizeX, centerY+sizeY, centerZ-sizeZ)
1089 local tbrx, tbry, tbrz = localToWorld(markerStart, centerX+sizeX, centerY+sizeY, centerZ-sizeZ)
1090 local tflx, tfly, tflz = localToWorld(markerStart, centerX-sizeX, centerY+sizeY, centerZ+sizeZ)
1091 local tfrx, tfry, tfrz = localToWorld(markerStart, centerX+sizeX, centerY+sizeY, centerZ+sizeZ)
1092
1093 table.insert(box.points, { blx, bly, blz } ) -- lower: lb
1094 table.insert(box.points, { brx, bry, brz } ) -- rb
1095 table.insert(box.points, { frx, fry, frz } ) -- rf
1096 table.insert(box.points, { flx, fly, flz } ) -- lf
1097
1098 table.insert(box.points, { tblx, tbly, tblz } ) -- upper: lb
1099 table.insert(box.points, { tbrx, tbry, tbrz } ) -- rb
1100 table.insert(box.points, { tfrx, tfry, tfrz } ) -- rf
1101 table.insert(box.points, { tflx, tfly, tflz } ) -- lf
1102 table.insert(box.points, { x, y, z } ) -- center
1103
1104 spec.checkBoxes[markerStart] = box
1105 end
1106
1107 local rx,ry,rz = getWorldRotation(markerStart)
1108 spec.objectsInTensionBeltRange = {}
1109 spec.numObjectsIntensionBeltRange = 0
1110
1111 overlapBox(x, y, z, rx, ry, rz, sizeX, sizeY, sizeZ, "objectOverlapCallback", self, CollisionMask.TRIGGER_DYNAMIC_MOUNT, true, false, true)
1112
1113 return spec.objectsInTensionBeltRange, spec.numObjectsIntensionBeltRange
1114end

initSpecialization

Description
Definition
initSpecialization()
Code
27function TensionBelts.initSpecialization()
28 g_configurationManager:addConfigurationType("tensionBelts", g_i18n:getText("configuration_tensionBelts"), "tensionBelts", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
29
30 local schema = Vehicle.xmlSchema
31 schema:setXMLSpecializationType("TensionBelts")
32
33 local key = "vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration(?).tensionBelts"
34 ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration(?)")
35
36 schema:register(XMLValueType.FLOAT, key .. "#totalInteractionRadius", "Total interaction radius", 6)
37 schema:register(XMLValueType.FLOAT, key .. "#interactionRadius", "Interaction radius", 1)
38 schema:register(XMLValueType.NODE_INDEX, key .. "#interactionBaseNode", "Interaction base node", "Vehicle root node")
39 schema:register(XMLValueType.NODE_INDEX, key .. "#activationTrigger", "Activation trigger")
40 schema:register(XMLValueType.STRING, key .. "#tensionBeltType", "Supports tension belts", "basic")
41
42 schema:register(XMLValueType.FLOAT, key .. "#width", "Belt width", "Used from belt definitions")
43 schema:register(XMLValueType.FLOAT, key .. "#ratchetPosition", "Ratchet position")
44 schema:register(XMLValueType.BOOL, key .. "#useHooks", "Use hooks", true)
45 schema:register(XMLValueType.FLOAT, key .. "#maxEdgeLength", "Max. edge length", 0.1)
46 schema:register(XMLValueType.FLOAT, key .. "#geometryBias", "Geometry bias", 0.01)
47 schema:register(XMLValueType.FLOAT, key .. "#defaultOffsetSide", "Default offset side", 0.1)
48 schema:register(XMLValueType.FLOAT, key .. "#defaultOffset", "Default offset", 0)
49 schema:register(XMLValueType.FLOAT, key .. "#defaultHeight", "Default height", 5)
50
51 schema:register(XMLValueType.BOOL, key .. "#allowFoldingWhileFasten", "Folding is allowed while tension belts are fasten", true)
52
53 schema:register(XMLValueType.NODE_INDEX, key .. "#linkNode", "Link node")
54 schema:register(XMLValueType.NODE_INDEX, key .. "#rootNode", "Root node", "Root component")
55 schema:register(XMLValueType.NODE_INDEX, key .. "#jointNode", "Joint node", "rootNode")
56
57 schema:register(XMLValueType.NODE_INDEX, key .. ".tensionBelt(?)#startNode", "Start node")
58 schema:register(XMLValueType.NODE_INDEX, key .. ".tensionBelt(?)#endNode", "End node")
59 schema:register(XMLValueType.FLOAT, key .. ".tensionBelt(?)#offsetLeft", "Offset left")
60 schema:register(XMLValueType.FLOAT, key .. ".tensionBelt(?)#offsetRight", "Offset right")
61 schema:register(XMLValueType.FLOAT, key .. ".tensionBelt(?)#offset", "Offset")
62 schema:register(XMLValueType.FLOAT, key .. ".tensionBelt(?)#height", "Height")
63 schema:register(XMLValueType.NODE_INDEX, key .. ".tensionBelt(?).intersectionNode(?)#node", "Intersection node")
64
65 SoundManager.registerSampleXMLPaths(schema, key .. ".sounds", "toggleBelt")
66 SoundManager.registerSampleXMLPaths(schema, key .. ".sounds", "addBelt")
67 SoundManager.registerSampleXMLPaths(schema, key .. ".sounds", "removeBelt")
68
69 schema:setXMLSpecializationType()
70
71 local schemaSavegame = Vehicle.xmlSchemaSavegame
72 schemaSavegame:register(XMLValueType.BOOL, "vehicles.vehicle(?).tensionBelts.belt(?)#isActive", "Belt is active", false)
73end

lockTensionBeltObject

Description
Definition
lockTensionBeltObject()
Code
703function TensionBelts:lockTensionBeltObject(objectId, objectsToJointTable, isDynamic, jointNode, object)
704 if objectsToJointTable[objectId] == nil then
705 local useDynamicMount = false
706 local useKinematicMount = false
707 local useSplitShapeMount = false
708
709 if isDynamic then
710 if self.isServer then
711 useDynamicMount = true
712 end
713 else
714 if object ~= nil and object.mountKinematic ~= nil then
715 local allowKinematicMounting = true
716 if object.getSupportsMountKinematic ~= nil and not object:getSupportsMountKinematic() then
717 allowKinematicMounting = false
718 end
719
720 if object.rootVehicle ~= nil then
721 local vehicles = object.rootVehicle.childVehicles
722 if #vehicles > 1 then
723 allowKinematicMounting = false
724 end
725 end
726
727 if allowKinematicMounting then
728 useKinematicMount = true
729 else
730 useDynamicMount = true
731 end
732 else
733 -- only for split shapes on server side
734 if self.isServer then
735 useSplitShapeMount = true
736 end
737 end
738 end
739
740 if useDynamicMount then
741 local constr = JointConstructor.new()
742 constr:setActors(jointNode, objectId)
743
744 -- create joint at center of mass to avoid jittering (e.g. tree trunks pivots are not at center of mass position)
745 -- create a transformGroup at the joint position to move the joint afterwards based on this transformGroup
746 local jointTransform = createTransformGroup("tensionBeltJoint")
747 link(self.spec_tensionBelts.linkNode, jointTransform)
748 local x,y,z = localToWorld(objectId, getCenterOfMass(objectId))
749 setWorldTranslation(jointTransform, x,y,z)
750
751 constr:setJointTransforms(jointTransform, jointTransform)
752
753 constr:setRotationLimit(0, 0, 0)
754 constr:setRotationLimit(1, 0, 0)
755 constr:setRotationLimit(2, 0, 0)
756
757 local springForce = 1000
758 local springDamping = 10
759 constr:setRotationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping)
760 constr:setTranslationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping)
761 local jointIndex = constr:finalize()
762
763 if object ~= nil then
764 if object.setReducedComponentMass ~= nil then
765 object:setReducedComponentMass(true)
766 self:setMassDirty()
767 end
768 if object.setCanBeSold ~= nil then
769 object:setCanBeSold(false)
770 end
771 end
772
773 objectsToJointTable[objectId] = {jointIndex=jointIndex, jointTransform=jointTransform, object=object}
774 elseif useKinematicMount then
775 local parentNode = getParent(objectId)
776 local x, y, z = localToLocal(objectId, jointNode, 0, 0, 0)
777 local rx, ry, rz = localRotationToLocal(objectId, jointNode, 0, 0, 0)
778
779 object:mountKinematic(self, jointNode, x, y, z, rx, ry, rz)
780
781 objectsToJointTable[objectId] = {parent=parentNode, object=object}
782 elseif useSplitShapeMount then
783 local parentNode = getParent(objectId)
784 local x, y, z = localToLocal(objectId, jointNode, 0, 0, 0)
785 local rx, ry, rz = localRotationToLocal(objectId, jointNode, 0, 0, 0)
786
787 setRigidBodyType(objectId, RigidBodyType.KINEMATIC)
788 link(jointNode, objectId)
789 setTranslation(objectId, x, y, z)
790 setRotation(objectId, rx, ry, rz)
791 objectsToJointTable[objectId] = {parent=parentNode, object=object}
792 end
793 end
794end

objectOverlapCallback

Description
Overlap callback
Definition
objectOverlapCallback(integer transformId)
Arguments
integertransformIdid of found transform
Code
1152function TensionBelts:objectOverlapCallback(transformId)
1153 if transformId ~= 0 and getHasClassId(transformId, ClassIds.SHAPE) then
1154 local spec = self.spec_tensionBelts
1155
1156 local object = g_currentMission:getNodeObject(transformId)
1157 if object ~= nil and object ~= self and (object.rootVehicle ~= self.rootVehicle) then
1158 if object.getSupportsTensionBelts ~= nil and object:getSupportsTensionBelts() then
1159 if object.getMeshNodes ~= nil and object.dynamicMountObject == nil then
1160 local nodeId = object:getTensionBeltNodeId()
1161 if spec.objectsInTensionBeltRange[nodeId] == nil then
1162 local nodes = object:getMeshNodes()
1163 if nodes ~= nil then
1164 spec.objectsInTensionBeltRange[nodeId] = {physics=nodeId, visuals=nodes, object=object}
1165 spec.numObjectsIntensionBeltRange = spec.numObjectsIntensionBeltRange + 1
1166 end
1167 end
1168 end
1169 end
1170 elseif getSplitType(transformId) ~= 0 then
1171 local rigidBodyType = getRigidBodyType(transformId)
1172 if (rigidBodyType == RigidBodyType.DYNAMIC or rigidBodyType == RigidBodyType.KINEMATIC) and spec.objectsInTensionBeltRange[transformId] == nil then
1173 spec.objectsInTensionBeltRange[transformId] = {physics=transformId, visuals={transformId}}
1174 spec.numObjectsIntensionBeltRange = spec.numObjectsIntensionBeltRange + 1
1175 end
1176 end
1177 end
1178
1179 return true
1180end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
384function TensionBelts:onDelete()
385 local spec = self.spec_tensionBelts
386
387 spec.isPlayerInRange = false
388 g_currentMission.activatableObjectsSystem:removeActivatable(spec.activatable)
389 self:setTensionBeltsActive(false, nil, true, false)
390
391 if spec.activationTrigger ~= nil then
392 removeTrigger(spec.activationTrigger)
393 spec.activationTrigger = nil
394 end
395
396 g_soundManager:deleteSamples(spec.samples)
397end

onDraw

Description
Called on draw
Definition
onDraw(boolean isActiveForInput, boolean isSelected)
Arguments
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
607function TensionBelts:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
608 local spec = self.spec_tensionBelts
609
610 if not spec.hasTensionBelts then
611 return
612 end
613
614 if isActiveForInputIgnoreSelection and isSelected then
615 if spec.areBeltsFasten then
616 g_currentMission:addHelpButtonText(g_i18n:getText("action_unfastenTensionBelts"), InputBinding.TOGGLE_TENSION_BELTS, nil, GS_PRIO_NORMAL)
617 else
618 g_currentMission:addHelpButtonText(g_i18n:getText("action_fastenTensionBelts"), InputBinding.TOGGLE_TENSION_BELTS, nil, GS_PRIO_NORMAL)
619 end
620 end
621
622-- for _, d in pairs(spec.objectsToJoint) do
623-- local node = d.jointTransform
624-- DebugUtil.drawDebugNode(node, getName(node))
625-- end
626end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
123function TensionBelts:onLoad(savegame)
124 local spec = self.spec_tensionBelts
125
126 local tensionBeltConfigurationId = Utils.getNoNil(self.configurations["tensionBelts"], 1)
127 local configKey = string.format("vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration(%d).tensionBelts", tensionBeltConfigurationId -1)
128 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration", tensionBeltConfigurationId , self.components, self)
129
130
131 spec.hasTensionBelts = true
132 if not self.xmlFile:hasProperty(configKey) then
133 spec.hasTensionBelts = false
134
135 SpecializationUtil.removeEventListener(self, "onPostLoad", TensionBelts)
136 SpecializationUtil.removeEventListener(self, "onDelete", TensionBelts)
137 SpecializationUtil.removeEventListener(self, "onPreDelete", TensionBelts)
138 SpecializationUtil.removeEventListener(self, "onReadStream", TensionBelts)
139 SpecializationUtil.removeEventListener(self, "onWriteStream", TensionBelts)
140 SpecializationUtil.removeEventListener(self, "onUpdate", TensionBelts)
141 SpecializationUtil.removeEventListener(self, "onUpdateTick", TensionBelts)
142 SpecializationUtil.removeEventListener(self, "onDraw", TensionBelts)
143 SpecializationUtil.removeEventListener(self, "onRegisterActionEvents", TensionBelts)
144
145 return
146 end
147
148 spec.belts = {}
149 spec.tensionBelts = {}
150 spec.singleBelts = {}
151 spec.sortedBelts = {}
152
153 spec.activatable = TensionBeltsActivatable.new(self)
154
155 spec.totalInteractionRadius = self.xmlFile:getValue(configKey.."#totalInteractionRadius", 6)
156 spec.interactionRadius = self.xmlFile:getValue(configKey.."#interactionRadius", 1)
157 spec.interactionBaseNode = self.xmlFile:getValue(configKey.."#interactionBaseNode", self.rootNode, self.components, self.i3dMappings)
158 spec.activationTrigger = self.xmlFile:getValue(configKey.."#activationTrigger", nil, self.components, self.i3dMappings)
159 if spec.activationTrigger ~= nil then
160 if not CollisionFlag.getHasFlagSet(spec.activationTrigger, CollisionFlag.TRIGGER_PLAYER) then
161 Logging.xmlError(self.xmlFile, "Missing player collision mask bit '%d' for tension belt trigger.", CollisionFlag.getBit(CollisionFlag.TRIGGER_PLAYER))
162 else
163 addTrigger(spec.activationTrigger, "tensionBeltActivationTriggerCallback", self)
164 end
165 end
166
167 spec.allowFoldingWhileFasten = self.xmlFile:getValue(configKey.."#allowFoldingWhileFasten", true)
168
169 spec.isPlayerInTrigger = false
170 spec.checkSizeOffsets = {0*0.5, 5*0.5, 3*0.5}
171 spec.numObjectsIntensionBeltRange = 0
172
173 local tensionBeltType = self.xmlFile:getValue(configKey.."#tensionBeltType", "basic")
174 local beltData = g_tensionBeltManager:getBeltData(tensionBeltType)
175
176 if beltData ~= nil then
177 spec.width = self.xmlFile:getValue(configKey.."#width")
178 spec.ratchetPosition = self.xmlFile:getValue(configKey.."#ratchetPosition")
179 spec.useHooks = self.xmlFile:getValue(configKey.."#useHooks", true)
180 spec.maxEdgeLength = self.xmlFile:getValue(configKey.."#maxEdgeLength", 0.1)
181 spec.geometryBias = self.xmlFile:getValue(configKey.."#geometryBias", 0.01)
182 spec.defaultOffsetSide = self.xmlFile:getValue(configKey.."#defaultOffsetSide", 0.1)
183 spec.defaultOffset = self.xmlFile:getValue(configKey.."#defaultOffset", 0)
184 spec.defaultHeight = self.xmlFile:getValue(configKey.."#defaultHeight", 5)
185 spec.beltData = beltData
186 spec.linkNode = self.xmlFile:getValue(configKey.."#linkNode", nil, self.components, self.i3dMappings)
187 spec.rootNode = self.xmlFile:getValue(configKey.."#rootNode", self.components[1].node, self.components, self.i3dMappings)
188 spec.jointNode = self.xmlFile:getValue(configKey.."#jointNode", spec.rootNode, self.components, self.i3dMappings)
189 spec.checkTimerDuration = 500
190 spec.checkTimer = spec.checkTimerDuration
191
192 if spec.linkNode == nil then
193 Logging.xmlError(self.xmlFile, "No tension belts link node given at %s%s", configKey, "#linkNode")
194 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
195 return
196 end
197
198 if getRigidBodyType(spec.jointNode) ~= RigidBodyType.DYNAMIC and getRigidBodyType(spec.jointNode) ~= RigidBodyType.KINEMATIC then
199 Logging.xmlError(self.xmlFile, "Given jointNode '"..getName(spec.jointNode).."' has invalid rigidBodyType. Have to be 'Dynamic' or 'Kinematic'! Using '"..getName(self.components[1].node).."' instead!")
200 spec.jointNode = self.components[1].node
201 end
202
203 local rigidBodyType = getRigidBodyType(spec.jointNode)
204 spec.isDynamic = rigidBodyType == RigidBodyType.DYNAMIC
205
206 local x,y,z = localToLocal(spec.linkNode, spec.jointNode, 0,0,0)
207 local rx,ry,rz = localRotationToLocal(spec.linkNode, spec.jointNode, 0,0,0)
208 spec.linkNodePosition = {x, y, z}
209 spec.linkNodeRotation = {rx, ry, rz}
210
211 spec.jointComponent = self:getParentComponent(spec.jointNode)
212
213 local i = 0
214 while true do
215 local key = string.format(configKey..".tensionBelt(%d)", i)
216 if not self.xmlFile:hasProperty(key) then
217 break
218 end
219
220 if #spec.sortedBelts == 2^TensionBelts.NUM_SEND_BITS then
221 Logging.xmlWarning(self.xmlFile, "Max number of tension belts is ".. 2^TensionBelts.NUM_SEND_BITS.."!")
222 break
223 end
224
225 local startNode = self.xmlFile:getValue(key.."#startNode", nil, self.components, self.i3dMappings)
226 local endNode = self.xmlFile:getValue(key.."#endNode", nil, self.components, self.i3dMappings)
227 if startNode ~= nil and endNode ~= nil then
228 local endX,endY,_ = getTranslation(endNode)
229 if math.abs(endX) < 0.0001 and math.abs(endY) < 0.0001 then
230 if spec.linkNode == nil then
231 spec.linkNode = getParent(startNode)
232 end
233 if spec.startNode == nil then
234 spec.startNode = startNode
235 end
236 spec.endNode = endNode
237
238 local offsetLeft = self.xmlFile:getValue(key.."#offsetLeft")
239 local offsetRight = self.xmlFile:getValue(key.."#offsetRight")
240 local offset = self.xmlFile:getValue(key.."#offset")
241 local height = self.xmlFile:getValue(key.."#height")
242
243 local intersectionNodes = {}
244 local j = 0
245 while true do
246 local intersectionKey = string.format(key..".intersectionNode(%d)", j)
247 if not self.xmlFile:hasProperty(intersectionKey) then
248 break
249 end
250 local node = self.xmlFile:getValue(intersectionKey.."#node", nil, self.components, self.i3dMappings)
251 if node ~= nil then
252 table.insert(intersectionNodes, node)
253 end
254 j = j + 1
255 end
256
257 local belt = {id=i+1, startNode=startNode, endNode=endNode, offsetLeft=offsetLeft, offsetRight=offsetRight, offset=offset, height=height, mesh=nil, intersectionNodes=intersectionNodes, dummy=nil, objectsToMount=nil}
258 spec.singleBelts[belt] = belt
259 table.insert(spec.sortedBelts, belt)
260 else
261 Logging.xmlWarning(self.xmlFile, "x and y position of endNode need to be 0 for tension belt '"..key.."'")
262 end
263 end
264
265 i = i + 1
266 end
267
268 local minX, minZ = math.huge, math.huge
269 local maxX, maxZ = -math.huge, -math.huge
270 for _, belt in pairs(spec.singleBelts) do
271 local sx,_,sz = localToLocal(belt.startNode, spec.interactionBaseNode, 0, 0, 0)
272 local ex,_,ez = localToLocal(belt.endNode, spec.interactionBaseNode, 0, 0, 0)
273 minX = math.min(minX, sx, ex)
274 minZ = math.min(minZ, sz, ez)
275 maxX = math.max(maxX, sx, ex)
276 maxZ = math.max(maxZ, sz, ez)
277 end
278
279 spec.interactionBasePointX = (maxX + minX) / 2
280 spec.interactionBasePointZ = (maxZ + minZ) / 2
281
282 for _, belt in pairs(spec.singleBelts) do
283 local sx,_,sz = localToLocal(belt.startNode, spec.interactionBaseNode, 0, 0, 0)
284 local sl = MathUtil.vector2Length(spec.interactionBasePointX-sx, spec.interactionBasePointZ-sz)+1
285 local el = MathUtil.vector2Length(spec.interactionBasePointX-sx, spec.interactionBasePointZ-sz)+1
286 spec.totalInteractionRadius = math.max(spec.totalInteractionRadius, sl, el)
287 end
288
289 else
290 Logging.xmlWarning(self.xmlFile, "No belt data found for tension belt type %s", tensionBeltType)
291 end
292
293 spec.hasTensionBelts = #spec.sortedBelts > 0
294
295 spec.checkBoxes = {}
296 spec.objectsToJoint = {}
297 spec.isPlayerInRange = false
298 spec.currentBelt = nil
299 spec.areBeltsFasten = false
300 spec.fastedAllBeltsIndex = -1
301 spec.fastedAllBeltsState = true
302
303 if self.isClient then
304 spec.samples = {}
305 spec.samples.toggleBelt = g_soundManager:loadSampleFromXML(self.xmlFile, configKey .. ".sounds", "toggleBelt", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
306 spec.samples.addBelt = g_soundManager:loadSampleFromXML(self.xmlFile, configKey .. ".sounds", "addBelt", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
307 spec.samples.removeBelt = g_soundManager:loadSampleFromXML(self.xmlFile, configKey .. ".sounds", "removeBelt", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
308 end
309
310 spec.texts = {}
311 spec.texts.warningFoldingTensionBelts = g_i18n:getText("warning_foldingNotWhileTensionBeltsFasten")
312
313 if not spec.hasTensionBelts then
314 SpecializationUtil.removeEventListener(self, "onPostLoad", TensionBelts)
315 SpecializationUtil.removeEventListener(self, "onDelete", TensionBelts)
316 SpecializationUtil.removeEventListener(self, "onPreDelete", TensionBelts)
317 SpecializationUtil.removeEventListener(self, "onReadStream", TensionBelts)
318 SpecializationUtil.removeEventListener(self, "onWriteStream", TensionBelts)
319 SpecializationUtil.removeEventListener(self, "onUpdate", TensionBelts)
320 SpecializationUtil.removeEventListener(self, "onUpdateTick", TensionBelts)
321 SpecializationUtil.removeEventListener(self, "onDraw", TensionBelts)
322 SpecializationUtil.removeEventListener(self, "onRegisterActionEvents", TensionBelts)
323
324 -- delete activation trigger as onDelete event is removed
325 if spec.activationTrigger ~= nil then
326 removeTrigger(spec.activationTrigger)
327 spec.activationTrigger = nil
328 end
329 else
330 g_messageCenter:subscribe(MessageType.TREE_SHAPE_CUT, self.onTensionBeltTreeShapeCut, self)
331 end
332end

onPostLoad

Description
Called after loading
Definition
onPostLoad(table savegame)
Arguments
tablesavegamesavegame
Code
337function TensionBelts:onPostLoad(savegame)
338 if savegame ~= nil then
339 local spec = self.spec_tensionBelts
340
341 spec.beltsToLoad = {}
342 local i = 0
343 while true do
344 local key = string.format("%s.tensionBelts.belt(%d)", savegame.key, i)
345 if not savegame.xmlFile:hasProperty(key) then
346 break
347 end
348 if savegame.xmlFile:getValue(key.."#isActive") then
349 table.insert(spec.beltsToLoad, i+1)
350 end
351 i = i + 1
352 end
353 end
354end

onPreDelete

Description
Definition
onPreDelete()
Code
371function TensionBelts:onPreDelete()
372 if self.spec_tensionBelts.sortedBelts ~= nil then
373 for _, belt in pairs(self.spec_tensionBelts.sortedBelts) do
374 local objects, _ = self:getObjectToMount(belt)
375 for id, _ in pairs(objects) do
376 I3DUtil.wakeUpObject(id)
377 end
378 end
379 end
380end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
403function TensionBelts:onReadStream(streamId, connection)
404 local spec = self.spec_tensionBelts
405
406 if spec.tensionBelts ~= nil then
407 spec.beltsToLoad = {}
408 for k, _ in ipairs(spec.sortedBelts) do
409 local beltActive = streamReadBool(streamId)
410 if beltActive then
411 table.insert(spec.beltsToLoad, k)
412 end
413 end
414 end
415end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
1327function TensionBelts:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
1328 local spec = self.spec_tensionBelts
1329 if self.isClient and spec.hasTensionBelts then
1330 self:clearActionEventsTable(spec.actionEvents)
1331
1332 if isActiveForInputIgnoreSelection then
1333 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_TENSION_BELTS, self, TensionBelts.actionEventToggleTensionBelts, false, true, false, true, nil)
1334 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
1335 end
1336 end
1337end

onTensionBeltTreeShapeCut

Description
Definition
onTensionBeltTreeShapeCut()
Code
1359function TensionBelts:onTensionBeltTreeShapeCut(oldShape, shape)
1360 if self.isServer then
1361 local spec = self.spec_tensionBelts
1362 for objectId, data in pairs(spec.objectsToJoint) do
1363 if objectId == oldShape then
1364 self:setAllTensionBeltsActive(false)
1365 end
1366 end
1367 end
1368end

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
436function TensionBelts:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
437 local spec = self.spec_tensionBelts
438
439 if spec.beltsToLoad ~= nil then
440 if #spec.beltsToLoad > 0 then
441 local beltIndex = spec.beltsToLoad[#spec.beltsToLoad]
442
443 local noEventSend = false
444 if not self.isServer then
445 -- do not resend event to server after sync. Only send event after loading to make sure client have visible tension belts
446 noEventSend = true
447 end
448 self:setTensionBeltsActive(true, spec.sortedBelts[beltIndex].id, noEventSend, false)
449
450 table.remove(spec.beltsToLoad, #spec.beltsToLoad)
451 else
452 spec.beltsToLoad = nil
453 end
454 end
455
456 if self.isServer and spec.isDynamic then
457 local x,y,z = localToLocal(spec.linkNode, spec.jointNode, 0,0,0)
458 local rx,ry,rz = localRotationToLocal(spec.linkNode, spec.jointNode, 0,0,0)
459
460 local isDirty = false
461 if math.abs(x - spec.linkNodePosition[1]) > 0.001 or math.abs(y - spec.linkNodePosition[2]) > 0.001 or math.abs(z - spec.linkNodePosition[3]) > 0.001 or
462 math.abs(rx - spec.linkNodeRotation[1]) > 0.001 or math.abs(ry - spec.linkNodeRotation[2]) > 0.001 or math.abs(rz - spec.linkNodeRotation[3]) > 0.001 then
463 isDirty = true
464 end
465 if isDirty then
466 spec.linkNodePosition[1], spec.linkNodePosition[2], spec.linkNodePosition[3] = x, y, z
467 spec.linkNodeRotation[1], spec.linkNodeRotation[2], spec.linkNodeRotation[3] = rx, ry, rz
468 for _, joint in pairs(spec.objectsToJoint) do
469 setJointFrame(joint.jointIndex, 0, joint.jointTransform)
470 end
471 end
472 end
473
474 if self.isClient then
475 if spec.fastedAllBeltsIndex > 0 then
476 local belt = spec.sortedBelts[spec.fastedAllBeltsIndex]
477 if belt ~= nil then
478 self:setTensionBeltsActive(spec.fastedAllBeltsState, belt.id, false)
479 end
480
481 spec.fastedAllBeltsIndex = spec.fastedAllBeltsIndex + 1
482 if spec.fastedAllBeltsIndex > #spec.sortedBelts then
483 spec.fastedAllBeltsIndex = -1
484 end
485 end
486 end
487
488 if TensionBelts.debugRendering then
489 for belt,_ in pairs(spec.belts) do
490 DebugUtil.drawDebugNode(belt)
491 for i=0, getNumOfChildren(belt)-1 do
492 DebugUtil.drawDebugNode(getChildAt(belt, i))
493 end
494 end
495
496 if spec.checkBoxes ~= nil then
497 for _, box in pairs(spec.checkBoxes) do
498 local p = box.points
499 local c = box.color
500
501 -- bottom
502 drawDebugLine(p[1][1],p[1][2],p[1][3], c[1],c[2],c[3], p[2][1],p[2][2],p[2][3], c[1],c[2],c[3])
503 drawDebugLine(p[2][1],p[2][2],p[2][3], c[1],c[2],c[3], p[3][1],p[3][2],p[3][3], c[1],c[2],c[3])
504 drawDebugLine(p[3][1],p[3][2],p[3][3], c[1],c[2],c[3], p[4][1],p[4][2],p[4][3], c[1],c[2],c[3])
505 drawDebugLine(p[4][1],p[4][2],p[4][3], c[1],c[2],c[3], p[1][1],p[1][2],p[1][3], c[1],c[2],c[3])
506 -- top
507 drawDebugLine(p[5][1],p[5][2],p[5][3], c[1],c[2],c[3], p[6][1],p[6][2],p[6][3], c[1],c[2],c[3])
508 drawDebugLine(p[6][1],p[6][2],p[6][3], c[1],c[2],c[3], p[7][1],p[7][2],p[7][3], c[1],c[2],c[3])
509 drawDebugLine(p[7][1],p[7][2],p[7][3], c[1],c[2],c[3], p[8][1],p[8][2],p[8][3], c[1],c[2],c[3])
510 drawDebugLine(p[8][1],p[8][2],p[8][3], c[1],c[2],c[3], p[5][1],p[5][2],p[5][3], c[1],c[2],c[3])
511 -- left
512 drawDebugLine(p[1][1],p[1][2],p[1][3], c[1],c[2],c[3], p[5][1],p[5][2],p[5][3], c[1],c[2],c[3])
513 drawDebugLine(p[4][1],p[4][2],p[4][3], c[1],c[2],c[3], p[8][1],p[8][2],p[8][3], c[1],c[2],c[3])
514 -- right
515 drawDebugLine(p[2][1],p[2][2],p[2][3], c[1],c[2],c[3], p[6][1],p[6][2],p[6][3], c[1],c[2],c[3])
516 drawDebugLine(p[3][1],p[3][2],p[3][3], c[1],c[2],c[3], p[7][1],p[7][2],p[7][3], c[1],c[2],c[3])
517 drawDebugPoint(p[9][1], p[9][2], p[9][3], 1, 1, 1, 1)
518 end
519 end
520
521 local a,b,c = localToWorld(spec.interactionBaseNode, spec.interactionBasePointX, 0, spec.interactionBasePointZ)
522 drawDebugPoint(a,b,c, 0,0,1, 1,1,1,1)
523
524 for i=0, 360-10, 10 do
525 local x,y,z = localToWorld(spec.interactionBaseNode, spec.interactionBasePointX+math.cos(math.rad(i))*spec.totalInteractionRadius,0, spec.interactionBasePointZ+math.sin(math.rad(i))*spec.totalInteractionRadius)
526 drawDebugPoint(x, y, z, 1,1,1,1)
527 for _, belt in pairs(spec.singleBelts) do
528 x,y,z = localToWorld(belt.startNode, math.cos(math.rad(i))*spec.interactionRadius, 0, math.sin(math.rad(i))*spec.interactionRadius)
529 drawDebugPoint(x, y, z, 0,1,0,1)
530 x,y,z = localToWorld(belt.endNode, math.cos(math.rad(i))*spec.interactionRadius, 0, math.sin(math.rad(i))*spec.interactionRadius)
531 drawDebugPoint(x, y, z, 1,0,0,1)
532 end
533 end
534 end
535
536 if spec.isPlayerInTrigger or spec.isPlayerInRange then
537 self:raiseActive()
538 end
539
540 -- create tension belt preview and control activation
541 local currentBelt
542 local wasInRange = spec.isPlayerInRange
543 spec.isPlayerInRange, currentBelt = self:getIsPlayerInTensionBeltsRange()
544 if spec.isPlayerInRange then
545 if currentBelt ~= spec.currentBelt then
546 if spec.currentBelt ~= nil and spec.currentBelt.dummy ~= nil then
547 delete(spec.currentBelt.dummy)
548 spec.currentBelt.dummy = nil
549 end
550 spec.currentBelt = currentBelt
551
552 if spec.currentBelt ~= nil and spec.currentBelt.mesh == nil then
553 local objects, _ = self:getObjectToMount(spec.currentBelt)
554 self:createTensionBelt(spec.currentBelt, true, objects)
555 end
556 end
557 g_currentMission.activatableObjectsSystem:addActivatable(spec.activatable)
558 else
559 if wasInRange then
560 g_currentMission.activatableObjectsSystem:removeActivatable(spec.activatable)
561 if spec.currentBelt ~= nil and spec.currentBelt.dummy ~= nil then
562 delete(spec.currentBelt.dummy)
563 spec.currentBelt.dummy = nil
564 spec.currentBelt = nil
565 end
566 end
567 end
568end

onUpdateTick

Description
Called on update tick
Definition
onUpdateTick(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
575function TensionBelts:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
576 local spec = self.spec_tensionBelts
577
578 if not spec.hasTensionBelts then
579 return
580 end
581
582 if self.isServer and spec.tensionBelts ~= nil then
583 spec.checkTimer = spec.checkTimer - dt
584 if spec.checkTimer < 0 then
585 -- check if entities have been deleted
586 local needUpdate = false
587 for phyiscObject, _ in pairs(spec.objectsToJoint) do
588 if not entityExists(phyiscObject) then
589 spec.objectsToJoint[phyiscObject] = nil
590 needUpdate = true
591 break
592 end
593 end
594 if needUpdate then
595 self:refreshTensionBelts()
596 end
597
598 spec.checkTimer = spec.checkTimerDuration
599 end
600 end
601end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
421function TensionBelts:onWriteStream(streamId, connection)
422 local spec = self.spec_tensionBelts
423
424 if spec.tensionBelts ~= nil then
425 for _, belt in ipairs(spec.sortedBelts) do
426 streamWriteBool(streamId, belt.mesh ~= nil)
427 end
428 end
429end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
21function TensionBelts.prerequisitesPresent(specializations)
22 return true
23end

refreshTensionBelts

Description
Definition
refreshTensionBelts()
Code
630function TensionBelts:refreshTensionBelts()
631 if self.isServer then
632 if g_server ~= nil then
633 g_server:broadcastEvent(TensionBeltsRefreshEvent.new(self), nil, nil, self)
634 end
635 end
636 for _, belt in pairs(self.spec_tensionBelts.sortedBelts) do
637 if belt.mesh ~= nil then
638 self:removeTensionBelt(belt)
639 local objects, _ = self:getObjectToMount(belt)
640 self:createTensionBelt(belt, false, objects)
641 end
642 end
643end

registerEventListeners

Description
Definition
registerEventListeners()
Code
107function TensionBelts.registerEventListeners(vehicleType)
108 SpecializationUtil.registerEventListener(vehicleType, "onLoad", TensionBelts)
109 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", TensionBelts)
110 SpecializationUtil.registerEventListener(vehicleType, "onDelete", TensionBelts)
111 SpecializationUtil.registerEventListener(vehicleType, "onPreDelete", TensionBelts)
112 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", TensionBelts)
113 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", TensionBelts)
114 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", TensionBelts)
115 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", TensionBelts)
116 SpecializationUtil.registerEventListener(vehicleType, "onDraw", TensionBelts)
117 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", TensionBelts)
118end

registerFunctions

Description
Definition
registerFunctions()
Code
77function TensionBelts.registerFunctions(vehicleType)
78 SpecializationUtil.registerFunction(vehicleType, "createTensionBelt", TensionBelts.createTensionBelt)
79 SpecializationUtil.registerFunction(vehicleType, "removeTensionBelt", TensionBelts.removeTensionBelt)
80 SpecializationUtil.registerFunction(vehicleType, "setTensionBeltsActive", TensionBelts.setTensionBeltsActive)
81 SpecializationUtil.registerFunction(vehicleType, "setAllTensionBeltsActive", TensionBelts.setAllTensionBeltsActive)
82 SpecializationUtil.registerFunction(vehicleType, "objectOverlapCallback", TensionBelts.objectOverlapCallback)
83 SpecializationUtil.registerFunction(vehicleType, "getObjectToMount", TensionBelts.getObjectToMount)
84 SpecializationUtil.registerFunction(vehicleType, "getObjectsToUnmount", TensionBelts.getObjectsToUnmount)
85 SpecializationUtil.registerFunction(vehicleType, "updateFastenState", TensionBelts.updateFastenState)
86 SpecializationUtil.registerFunction(vehicleType, "refreshTensionBelts", TensionBelts.refreshTensionBelts)
87 SpecializationUtil.registerFunction(vehicleType, "freeTensionBeltObject", TensionBelts.freeTensionBeltObject)
88 SpecializationUtil.registerFunction(vehicleType, "lockTensionBeltObject", TensionBelts.lockTensionBeltObject)
89 SpecializationUtil.registerFunction(vehicleType, "getIsPlayerInTensionBeltsRange", TensionBelts.getIsPlayerInTensionBeltsRange)
90 SpecializationUtil.registerFunction(vehicleType, "getIsDynamicallyMountedNode", TensionBelts.getIsDynamicallyMountedNode)
91 SpecializationUtil.registerFunction(vehicleType, "tensionBeltActivationTriggerCallback", TensionBelts.tensionBeltActivationTriggerCallback)
92 SpecializationUtil.registerFunction(vehicleType, "onTensionBeltTreeShapeCut", TensionBelts.onTensionBeltTreeShapeCut)
93end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
97function TensionBelts.registerOverwrittenFunctions(vehicleType)
98 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsReadyForAutomatedTrainTravel", TensionBelts.getIsReadyForAutomatedTrainTravel)
99 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", TensionBelts.getCanBeSelected)
100 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsFoldAllowed", TensionBelts.getIsFoldAllowed)
101 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillLevelInformation", TensionBelts.getFillLevelInformation)
102 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAdditionalComponentMass", TensionBelts.getAdditionalComponentMass)
103end

removeTensionBelt

Description
Remove tension belt
Definition
removeTensionBelt(table belt, boolean playSound)
Arguments
tablebeltbelt to remove
booleanplaySoundplay sound (nil = true)
Code
995function TensionBelts:removeTensionBelt(belt, playSound)
996 if belt.mesh ~= nil then
997 local spec = self.spec_tensionBelts
998
999 spec.belts[belt.mesh] = nil
1000 delete(belt.mesh)
1001 belt.mesh = nil
1002 if spec.currentBelt == belt then
1003 spec.currentBelt = nil
1004 end
1005
1006 if belt.dummy == nil and playSound ~= false then
1007 if self.isClient then
1008 g_soundManager:playSample(spec.samples.toggleBelt)
1009 g_soundManager:playSample(spec.samples.removeBelt)
1010 end
1011 end
1012 end
1013end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
358function TensionBelts:saveToXMLFile(xmlFile, key, usedModNames)
359 local spec = self.spec_tensionBelts
360
361 if spec.hasTensionBelts then
362 for i, belt in ipairs(spec.sortedBelts) do
363 local beltKey = string.format("%s.belt(%d)", key, i-1)
364 xmlFile:setValue(beltKey.."#isActive", belt.mesh ~= nil)
365 end
366 end
367end

setAllTensionBeltsActive

Description
Set tensionbelts active state
Definition
setAllTensionBeltsActive()
Code
858function TensionBelts:setAllTensionBeltsActive(isActive, noEventSend)
859 local spec = self.spec_tensionBelts
860
861 if spec.hasTensionBelts then
862 isActive = Utils.getNoNil(isActive, not spec.areBeltsFasten)
863 for _, belt in pairs(spec.sortedBelts) do
864 self:setTensionBeltsActive(isActive, belt.id, noEventSend)
865 end
866 end
867end

setTensionBeltsActive

Description
Set tensionbelts active state
Definition
setTensionBeltsActive(boolean isActive, integer beltId, boolean playSound)
Arguments
booleanisActivenew active state
integerbeltIdid of belt to set state (if id is nil it uses every belt)
booleanplaySoundplay sound (nil = true)
Code
801function TensionBelts:setTensionBeltsActive(isActive, beltId, noEventSend, playSound)
802 local spec = self.spec_tensionBelts
803
804 if spec.tensionBelts ~= nil then
805 TensionBeltsEvent.sendEvent(self, isActive, beltId, noEventSend)
806
807 local belt = nil
808 if beltId ~= nil then
809 belt = spec.sortedBelts[beltId]
810 end
811
812 if isActive then
813 local objects, _ = self:getObjectToMount(belt)
814 if belt == nil then
815 for _, singleBelt in pairs(spec.singleBelts) do
816 if singleBelt.mesh == nil then
817 self:createTensionBelt(singleBelt, false, objects, playSound)
818 end
819 end
820 else
821 if belt.mesh == nil then
822 self:createTensionBelt(belt, false, objects, playSound)
823 end
824 end
825
826 for _, data in pairs(objects) do
827 self:lockTensionBeltObject(data.physics, spec.objectsToJoint, spec.isDynamic, spec.jointNode, data.object)
828 if data.object ~= nil then
829 data.object.tensionMountObject = self
830 end
831 end
832 else
833 if belt == nil then
834 for _, singleBelt in pairs(spec.singleBelts) do
835 self:removeTensionBelt(singleBelt, playSound)
836 end
837 else
838 self:removeTensionBelt(belt, playSound)
839 end
840
841 -- remove joints
842 local objectIds, _ = self:getObjectsToUnmount(belt)
843 for objectId, objectData in pairs(objectIds) do
844 self:freeTensionBeltObject(objectId, spec.objectsToJoint, spec.isDynamic, objectData.object)
845
846 if objectData.object ~= nil then
847 objectData.object.tensionMountObject = nil
848 end
849 end
850 end
851
852 self:updateFastenState()
853 end
854end

tensionBeltActivationTriggerCallback

Description
Definition
tensionBeltActivationTriggerCallback()
Code
1341function TensionBelts:tensionBeltActivationTriggerCallback(triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId)
1342 local spec = self.spec_tensionBelts
1343 if self.isClient and spec.hasTensionBelts then
1344 if onEnter or onLeave then
1345 if g_currentMission.player ~= nil and otherActorId == g_currentMission.player.rootNode then
1346 if onEnter then
1347 self:raiseActive()
1348 spec.isPlayerInTrigger = true
1349 else
1350 spec.isPlayerInTrigger = false
1351 end
1352 end
1353 end
1354 end
1355end

updateFastenState

Description
Update 'self.areBeltsFasten'
Definition
updateFastenState()
Code
871function TensionBelts:updateFastenState()
872 local spec = self.spec_tensionBelts
873
874 local unfastenBelts = false
875 for _, belt in pairs(spec.singleBelts) do
876 if belt.mesh == nil then
877 unfastenBelts = true
878 break
879 end
880 end
881
882 spec.areBeltsFasten = not unfastenBelts
883end