735 | function TensionBelts:createTensionBelt(belt, isDummy, objects) |
736 | local spec = self.spec_tensionBelts |
737 | |
738 | local tensionBelt = TensionBeltGeometryConstructor:new() |
739 | |
740 | local beltData = spec.beltData |
741 | |
742 | tensionBelt:setWidth(spec.width) |
743 | tensionBelt:setMaxEdgeLength(spec.maxEdgeLength) |
744 | if isDummy then |
745 | tensionBelt:setMaterial(beltData.dummyMaterial.materialId) |
746 | tensionBelt:setUVscale(beltData.dummyMaterial.uvScale) |
747 | else |
748 | tensionBelt:setMaterial(beltData.material.materialId) |
749 | tensionBelt:setUVscale(beltData.material.uvScale) |
750 | end |
751 | |
752 | if spec.ratchetPosition ~= nil and beltData.ratchet ~= nil then |
753 | tensionBelt:addAttachment(0, spec.ratchetPosition, beltData.ratchet.sizeRatio*spec.width) |
754 | end |
755 | |
756 | if spec.useHooks and beltData.hook ~= nil then |
757 | tensionBelt:addAttachment(0, 0, beltData.hook.sizeRatio*spec.width) |
758 | tensionBelt:addAttachment(1, 0, beltData.hook.sizeRatio*spec.width) |
759 | end |
760 | |
761 | tensionBelt:setFixedPoints(belt.startNode, belt.endNode) |
762 | tensionBelt:setGeometryBias(spec.geometryBias) |
763 | tensionBelt:setLinkNode(spec.linkNode) |
764 | |
765 | for _, pointNode in pairs(belt.intersectionNodes) do |
766 | local x,y,z = getWorldTranslation(pointNode) |
767 | local dirX, dirY, dirZ = localDirectionToWorld(pointNode, 1, 0, 0) |
768 | tensionBelt:addIntersectionPoint(x,y,z, dirX, dirY, dirZ) |
769 | end |
770 | |
771 | for _, object in pairs(objects) do |
772 | for _, node in pairs(object.visuals) do |
773 | if getSplitType(node) ~= 0 then |
774 | -- Allow a larger range of uvs for trees |
775 | tensionBelt:addShape(node, -100, 100, -100, 100) |
776 | else |
777 | tensionBelt:addShape(node, 0, 1, 0, 1) |
778 | end |
779 | end |
780 | end |
781 | |
782 | local beltShape, _, beltLength = tensionBelt:finalize() |
783 | if beltShape ~= 0 then |
784 | if isDummy then |
785 | belt.dummy = beltShape |
786 | else |
787 | local currentIndex = 0 |
788 | if spec.ratchetPosition ~= nil and beltData.ratchet ~= nil then |
789 | if getNumOfChildren(beltShape) > currentIndex then |
790 | local scale = spec.width |
791 | local ratched = clone(beltData.ratchet.node, false, false, false) |
792 | link(getChildAt(beltShape, 0), ratched) |
793 | setScale(ratched, scale, scale, scale) |
794 | currentIndex = currentIndex + 1 |
795 | end |
796 | end |
797 | if spec.useHooks then |
798 | if beltData.hook ~= nil and getNumOfChildren(beltShape) > currentIndex+1 then |
799 | local scale = spec.width |
800 | local hookStart = clone(beltData.hook.node, false, false, false) |
801 | link(getChildAt(beltShape, currentIndex), hookStart) |
802 | setScale(hookStart, scale, scale, scale) |
803 | |
804 | local hookEnd = clone(beltData.hook.node, false, false, false) |
805 | link(getChildAt(beltShape, currentIndex+1), hookEnd) |
806 | setRotation(hookEnd, 0, math.pi, 0) |
807 | setTranslation(hookEnd, 0, 0, beltData.hook.sizeRatio*spec.width) |
808 | setScale(hookEnd, scale, scale, scale) |
809 | currentIndex = currentIndex + 2 |
810 | |
811 | setShaderParameter(beltShape, "beltClipOffsets", 0, beltData.hook.sizeRatio*spec.width, beltLength-beltData.hook.sizeRatio*spec.width, beltLength, false) |
812 | end |
813 | end |
814 | |
815 | belt.mesh = beltShape |
816 | spec.belts[beltShape] = beltShape |
817 | if belt.dummy ~= nil then |
818 | delete(belt.dummy) |
819 | belt.dummy = nil |
820 | end |
821 | end |
822 | |
823 | return beltShape |
824 | end |
825 | |
826 | return nil |
827 | end |
850 | function TensionBelts:getObjectToMount(belt) |
851 | local spec = self.spec_tensionBelts |
852 | |
853 | local markerStart = spec.startNode |
854 | local markerEnd = spec.endNode |
855 | local offsetLeft = nil |
856 | local offsetRight = nil |
857 | local offset = nil |
858 | local height = nil |
859 | if belt ~= nil then |
860 | markerStart = belt.startNode |
861 | markerEnd = belt.endNode |
862 | |
863 | offsetLeft = belt.offsetLeft |
864 | offsetRight = belt.offsetRight |
865 | offset = belt.offset |
866 | height = belt.height |
867 | if offsetLeft == nil then |
868 | if spec.sortedBelts[belt.id-1] ~= nil and spec.sortedBelts[belt.id-1].mesh ~= nil then |
869 | local x,_,_ = localToLocal(markerStart, spec.sortedBelts[belt.id-1].startNode, 0, 0, 0) |
870 | offsetLeft = math.abs(x) |
871 | end |
872 | end |
873 | if offsetRight == nil then |
874 | if spec.sortedBelts[belt.id+1] ~= nil and spec.sortedBelts[belt.id+1].mesh ~= nil then |
875 | local x,_,_ = localToLocal(markerStart, spec.sortedBelts[belt.id+1].startNode, 0, 0, 0) |
876 | offsetRight = math.abs(x) |
877 | end |
878 | end |
879 | |
880 | end |
881 | |
882 | if offsetLeft == nil then |
883 | offsetLeft = spec.defaultOffsetSide |
884 | end |
885 | if offsetRight == nil then |
886 | offsetRight = spec.defaultOffsetSide |
887 | end |
888 | if offset == nil then |
889 | offset = spec.defaultOffset |
890 | end |
891 | if height == nil then |
892 | height = spec.defaultHeight |
893 | end |
894 | |
895 | local sizeX = (offsetLeft+offsetRight) * 0.5 |
896 | local sizeY = height * 0.5 |
897 | local _, _, width = localToLocal(markerEnd, markerStart, 0, 0, 0) |
898 | local sizeZ = width*0.5 - 2*offset |
899 | |
900 | local centerX = (offsetLeft-offsetRight)*0.5 |
901 | local centerY = height*0.5 |
902 | local centerZ = width*0.5 |
903 | local x,y,z = localToWorld(markerStart, centerX, centerY, centerZ) |
904 | |
905 | if TensionBelts.debugRendering then |
906 | local box = {} |
907 | box.points = {} |
908 | local colorR = math.random(0, 1) |
909 | local colorG = math.random(0, 1) |
910 | local colorB = math.random(0, 1) |
911 | box.color = {colorR,colorG,colorB} |
912 | |
913 | local blx, bly, blz = localToWorld(markerStart, centerX-sizeX, centerY-sizeY, centerZ-sizeZ) |
914 | local brx, bry, brz = localToWorld(markerStart, centerX+sizeX, centerY-sizeY, centerZ-sizeZ) |
915 | local flx, fly, flz = localToWorld(markerStart, centerX-sizeX, centerY-sizeY, centerZ+sizeZ) |
916 | local frx, fry, frz = localToWorld(markerStart, centerX+sizeX, centerY-sizeY, centerZ+sizeZ) |
917 | |
918 | local tblx, tbly, tblz = localToWorld(markerStart, centerX-sizeX, centerY+sizeY, centerZ-sizeZ) |
919 | local tbrx, tbry, tbrz = localToWorld(markerStart, centerX+sizeX, centerY+sizeY, centerZ-sizeZ) |
920 | local tflx, tfly, tflz = localToWorld(markerStart, centerX-sizeX, centerY+sizeY, centerZ+sizeZ) |
921 | local tfrx, tfry, tfrz = localToWorld(markerStart, centerX+sizeX, centerY+sizeY, centerZ+sizeZ) |
922 | |
923 | table.insert(box.points, { blx, bly, blz } ) -- lower: lb |
924 | table.insert(box.points, { brx, bry, brz } ) -- rb |
925 | table.insert(box.points, { frx, fry, frz } ) -- rf |
926 | table.insert(box.points, { flx, fly, flz } ) -- lf |
927 | |
928 | table.insert(box.points, { tblx, tbly, tblz } ) -- upper: lb |
929 | table.insert(box.points, { tbrx, tbry, tbrz } ) -- rb |
930 | table.insert(box.points, { tfrx, tfry, tfrz } ) -- rf |
931 | table.insert(box.points, { tflx, tfly, tflz } ) -- lf |
932 | table.insert(box.points, { x, y, z } ) -- center |
933 | |
934 | spec.checkBoxes[markerStart] = box |
935 | end |
936 | |
937 | local rx,ry,rz = getWorldRotation(markerStart) |
938 | spec.objectsInTensionBeltRange = {} |
939 | spec.numObjectsIntensionBeltRange = 0 |
940 | |
941 | -- collision mask : all bits except bit 13, 23, 30 |
942 | overlapBox(x, y, z, rx, ry, rz, sizeX, sizeY, sizeZ, "objectOverlapCallback", self, 3212828671, true, false, true) |
943 | |
944 | return spec.objectsInTensionBeltRange, spec.numObjectsIntensionBeltRange |
945 | end |
572 | function TensionBelts:lockTensionBeltObject(objectId, objectsToJointTable, isDynamic, jointNode, object) |
573 | |
574 | if objectsToJointTable[objectId] == nil then |
575 | if isDynamic then |
576 | local constr = JointConstructor:new() |
577 | constr:setActors(jointNode, objectId) |
578 | |
579 | -- create joint at center of mass to avoid jittering (e.g. tree trunks pivots are not at center of mass position) |
580 | -- create a transformGroup at the joint position to move the joint afterwards based on this transformGroup |
581 | local jointTransform = createTransformGroup("tensionBeltJoint") |
582 | link(self.spec_tensionBelts.linkNode, jointTransform) |
583 | local x,y,z = localToWorld(objectId, getCenterOfMass(objectId)) |
584 | setWorldTranslation(jointTransform, x,y,z) |
585 | local rx,ry,rz = getWorldRotation(objectId) |
586 | setWorldRotation(jointTransform, rx,ry,rz) |
587 | |
588 | constr:setJointTransforms(jointTransform, jointTransform) |
589 | |
590 | constr:setRotationLimit(0, 0, 0) |
591 | constr:setRotationLimit(1, 0, 0) |
592 | constr:setRotationLimit(2, 0, 0) |
593 | local springForce = 7500 |
594 | local springDamping = 1500 |
595 | constr:setRotationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping) |
596 | constr:setTranslationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping) |
597 | local jointIndex = constr:finalize() |
598 | |
599 | objectsToJointTable[objectId] = {jointIndex=jointIndex, jointTransform=jointTransform} |
600 | |
601 | -- just testing, if enabled collisions have any benefit |
602 | --for obj, _ in pairs(objectsToJointTable) do |
603 | -- if obj ~= objectId then |
604 | -- setPairCollision(obj, objectId, false) |
605 | -- end |
606 | --end |
607 | else |
608 | local parentNode = getParent(objectId) |
609 | local x,y,z = localToLocal(objectId, jointNode, 0, 0, 0) |
610 | local a,b,c = localRotationToLocal(objectId, jointNode, 0, 0, 0) |
611 | setRigidBodyType(objectId, "Kinematic") |
612 | link(jointNode, objectId) |
613 | setTranslation(objectId, x, y, z) |
614 | setRotation(objectId, a, b, c) |
615 | objectsToJointTable[objectId] = {parent=parentNode} |
616 | |
617 | if object ~= nil then |
618 | if object.components ~= nil then |
619 | for _, component in ipairs(object.components) do |
620 | if component.node == objectId then |
621 | component.isKinematic = true |
622 | component.isDynamic = false |
623 | end |
624 | end |
625 | end |
626 | end |
627 | end |
628 | end |
629 | end |
74 | function TensionBelts:onLoad(savegame) |
75 | local spec = self.spec_tensionBelts |
76 | |
77 | local tensionBeltConfigurationId = Utils.getNoNil(self.configurations["tensionBelts"], 1) |
78 | local configKey = string.format("vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration(%d).tensionBelts", tensionBeltConfigurationId -1) |
79 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.tensionBelts.tensionBeltsConfigurations.tensionBeltsConfiguration", tensionBeltConfigurationId , self.components, self) |
80 | |
81 | |
82 | spec.hasTensionBelts = true |
83 | if not hasXMLProperty(self.xmlFile, configKey) then |
84 | spec.hasTensionBelts = false |
85 | return |
86 | end |
87 | |
88 | spec.belts = {} |
89 | spec.activatable = TensionBeltsActivatable:new(self) |
90 | |
91 | spec.totalInteractionRadius = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#totalInteractionRadius"), 6) |
92 | spec.interactionRadius = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#interactionRadius"), 1) |
93 | spec.interactionBaseNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey.."#interactionBasenode"), self.i3dMappings), self.rootNode) |
94 | spec.activationTrigger = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey.."#activationTrigger"), self.i3dMappings) |
95 | if spec.activationTrigger ~= nil then |
96 | addTrigger(spec.activationTrigger, "tensionBeltActivationTriggerCallback", self) |
97 | end |
98 | |
99 | spec.isPlayerInTrigger = false |
100 | spec.checkSizeOffsets = {0*0.5, 5*0.5, 3*0.5} |
101 | spec.numObjectsIntensionBeltRange = 0 |
102 | |
103 | local tensionBeltType = Utils.getNoNil(getXMLString(self.xmlFile, configKey.."#tensionBeltType"), "basic") |
104 | local beltData = g_tensionBeltManager:getBeltData(tensionBeltType) |
105 | |
106 | if beltData ~= nil then |
107 | spec.tensionBelts = {} |
108 | spec.singleBelts = {} |
109 | spec.sortedBelts = {} |
110 | spec.width = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#width"), 0.15) |
111 | spec.ratchetPosition = getXMLFloat(self.xmlFile, configKey.."#ratchetPosition") |
112 | spec.useHooks = Utils.getNoNil(getXMLBool(self.xmlFile, configKey.."#useHooks"), true) |
113 | spec.maxEdgeLength = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#maxEdgeLength"), 0.1) |
114 | spec.geometryBias = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#geometryBias"), 0.01) |
115 | spec.defaultOffsetSide = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#defaultOffsetSide"), 0.1) |
116 | spec.defaultOffset = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#defaultOffset"), 0) |
117 | spec.defaultHeight = Utils.getNoNil(getXMLFloat(self.xmlFile, configKey.."#defaultHeight"), 5) |
118 | spec.beltData = beltData |
119 | spec.linkNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey.."#linkNode"), self.i3dMappings) |
120 | spec.rootNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey.."#rootNode"), self.i3dMappings), self.components[1].node) |
121 | spec.jointNode = Utils.getNoNil(I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, configKey.."#jointNode"), self.i3dMappings), spec.rootNode) |
122 | spec.checkTimerDuration = 500 |
123 | spec.checkTimer = spec.checkTimerDuration |
124 | |
125 | if getRigidBodyType(spec.jointNode) ~= "Dynamic" and getRigidBodyType(spec.jointNode) ~= "Kinematic" then |
126 | print("Error: Given jointNode '"..getName(spec.jointNode).."' has invalid rigidBodyType. Have to be 'Dynamic' or 'Kinematic'! Using '"..getName(self.components[1].node).."' instead!") |
127 | spec.jointNode = self.components[1].node |
128 | end |
129 | |
130 | local rigidBodyType = getRigidBodyType(spec.jointNode) |
131 | spec.isDynamic = rigidBodyType == "Dynamic" |
132 | |
133 | local x,y,z = localToLocal(spec.linkNode, spec.jointNode, 0,0,0) |
134 | local rx,ry,rz = localRotationToLocal(spec.linkNode, spec.jointNode, 0,0,0) |
135 | spec.linkNodePosition = {x, y, z} |
136 | spec.linkNodeRotation = {rx, ry, rz} |
137 | |
138 | local i = 0 |
139 | while true do |
140 | local key = string.format(configKey..".tensionBelt(%d)", i) |
141 | if not hasXMLProperty(self.xmlFile, key) then |
142 | break |
143 | end |
144 | |
145 | if #spec.sortedBelts == 2^TensionBelts.NUM_SEND_BITS then |
146 | print("Warning: Max number of tension belts is ".. 2^TensionBelts.NUM_SEND_BITS.."!") |
147 | break |
148 | end |
149 | |
150 | local startNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#startNode"), self.i3dMappings) |
151 | local endNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#endNode"), self.i3dMappings) |
152 | if startNode ~= nil and endNode ~= nil then |
153 | local x,y,_ = localToLocal(endNode, startNode, 0, 0, 0) |
154 | |
155 | if math.abs(x) < 0.0001 and math.abs(y) < 0.0001 then |
156 | if spec.linkNode == nil then |
157 | spec.linkNode = getParent(startNode) |
158 | end |
159 | if spec.startNode == nil then |
160 | spec.startNode = startNode |
161 | end |
162 | spec.endNode = endNode |
163 | |
164 | local offsetLeft = getXMLFloat(self.xmlFile, key.."#offsetLeft") |
165 | local offsetRight = getXMLFloat(self.xmlFile, key.."#offsetRight") |
166 | local offset = getXMLFloat(self.xmlFile, key.."#offset") |
167 | local height = getXMLFloat(self.xmlFile, key.."#height") |
168 | |
169 | local intersectionNodes = {} |
170 | local j = 0 |
171 | while true do |
172 | local intersectionKey = string.format(key..".intersectionNode(%d)", j) |
173 | if not hasXMLProperty(self.xmlFile, intersectionKey) then |
174 | break |
175 | end |
176 | local node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, intersectionKey.."#node"), self.i3dMappings) |
177 | if node ~= nil then |
178 | table.insert(intersectionNodes, node) |
179 | end |
180 | j = j + 1 |
181 | end |
182 | |
183 | 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} |
184 | spec.singleBelts[belt] = belt |
185 | table.insert(spec.sortedBelts, belt) |
186 | else |
187 | print("Warning: x and y position of endNode need to be 0 for tension belt '"..key.."' in '"..self.configFileName.."'!") |
188 | end |
189 | end |
190 | |
191 | i = i + 1 |
192 | end |
193 | |
194 | local minX, minZ = math.huge, math.huge |
195 | local maxX, maxZ = -math.huge, -math.huge |
196 | for _, belt in pairs(spec.singleBelts) do |
197 | local sx,_,sz = localToLocal(belt.startNode, spec.interactionBaseNode, 0, 0, 0) |
198 | local ex,_,ez = localToLocal(belt.endNode, spec.interactionBaseNode, 0, 0, 0) |
199 | minX = math.min(minX, sx, ex) |
200 | minZ = math.min(minZ, sz, ez) |
201 | maxX = math.max(maxX, sx, ex) |
202 | maxZ = math.max(maxZ, sz, ez) |
203 | end |
204 | |
205 | spec.interactionBasePointX = (maxX + minX) / 2 |
206 | spec.interactionBasePointZ = (maxZ + minZ) / 2 |
207 | |
208 | for _, belt in pairs(spec.singleBelts) do |
209 | local sx,_,sz = localToLocal(belt.startNode, spec.interactionBaseNode, 0, 0, 0) |
210 | local sl = MathUtil.vector2Length(spec.interactionBasePointX-sx, spec.interactionBasePointZ-sz)+1 |
211 | local el = MathUtil.vector2Length(spec.interactionBasePointX-sx, spec.interactionBasePointZ-sz)+1 |
212 | spec.totalInteractionRadius = math.max(spec.totalInteractionRadius, sl, el) |
213 | end |
214 | |
215 | spec.hasTensionBelts = #spec.sortedBelts > 0 |
216 | else |
217 | print("Warning: No belt data found for tension belts in '"..self.configFileName.."'!") |
218 | end |
219 | |
220 | spec.checkBoxes = {} |
221 | spec.objectsToJoint = {} |
222 | spec.isPlayerInRange = false |
223 | spec.currentBelt = nil |
224 | spec.areBeltsFasten = false |
225 | end |
333 | function TensionBelts:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
334 | local spec = self.spec_tensionBelts |
335 | |
336 | if not spec.hasTensionBelts then |
337 | return |
338 | end |
339 | |
340 | if spec.beltsToLoad ~= nil then |
341 | for _, k in pairs(spec.beltsToLoad) do |
342 | local noEventSend = false |
343 | if not self.isServer then |
344 | -- do not resend event to server after sync. Only send event after loading to make sure client have visible tension belts |
345 | noEventSend = true |
346 | end |
347 | self:setTensionBeltsActive(true, spec.sortedBelts[k].id, noEventSend) |
348 | end |
349 | spec.beltsToLoad = nil |
350 | end |
351 | |
352 | if self.isServer and spec.isDynamic then |
353 | local x,y,z = localToLocal(spec.linkNode, spec.jointNode, 0,0,0) |
354 | local rx,ry,rz = localRotationToLocal(spec.linkNode, spec.jointNode, 0,0,0) |
355 | |
356 | local isDirty = false |
357 | 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 |
358 | 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 |
359 | isDirty = true |
360 | end |
361 | if isDirty then |
362 | spec.linkNodePosition[1], spec.linkNodePosition[2], spec.linkNodePosition[3] = x, y, z |
363 | spec.linkNodeRotation[1], spec.linkNodeRotation[2], spec.linkNodeRotation[3] = rx, ry, rz |
364 | for _, joint in pairs(spec.objectsToJoint) do |
365 | setJointFrame(joint.jointIndex, 0, joint.jointTransform) |
366 | end |
367 | end |
368 | end |
369 | |
370 | if TensionBelts.debugRendering then |
371 | for belt,_ in pairs(spec.belts) do |
372 | DebugUtil.drawDebugNode(belt) |
373 | for i=0, getNumOfChildren(belt)-1 do |
374 | DebugUtil.drawDebugNode(getChildAt(belt, i)) |
375 | end |
376 | end |
377 | |
378 | if spec.checkBoxes ~= nil then |
379 | for _, box in pairs(spec.checkBoxes) do |
380 | local p = box.points |
381 | local c = box.color |
382 | |
383 | -- bottom |
384 | 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]) |
385 | 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]) |
386 | 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]) |
387 | 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]) |
388 | -- top |
389 | 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]) |
390 | 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]) |
391 | 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]) |
392 | 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]) |
393 | -- left |
394 | 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]) |
395 | 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]) |
396 | -- right |
397 | 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]) |
398 | 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]) |
399 | drawDebugPoint(p[9][1], p[9][2], p[9][3], 1, 1, 1, 1) |
400 | end |
401 | end |
402 | |
403 | local a,b,c = localToWorld(spec.interactionBaseNode, spec.interactionBasePointX, 0, spec.interactionBasePointZ) |
404 | drawDebugPoint(a,b,c, 0,0,1, 1,1,1,1) |
405 | |
406 | for i=0, 360-10, 10 do |
407 | 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) |
408 | drawDebugPoint(x, y, z, 1,1,1,1) |
409 | for _, belt in pairs(spec.singleBelts) do |
410 | local x,y,z = localToWorld(belt.startNode, math.cos(math.rad(i))*spec.interactionRadius, 0, math.sin(math.rad(i))*spec.interactionRadius) |
411 | drawDebugPoint(x, y, z, 0,1,0,1) |
412 | local x,y,z = localToWorld(belt.endNode, math.cos(math.rad(i))*spec.interactionRadius, 0, math.sin(math.rad(i))*spec.interactionRadius) |
413 | drawDebugPoint(x, y, z, 1,0,0,1) |
414 | end |
415 | end |
416 | end |
417 | |
418 | if spec.isPlayerInTrigger or spec.isPlayerInRange then |
419 | self:raiseActive() |
420 | end |
421 | |
422 | -- create tension belt preview and control activation |
423 | local currentBelt = nil |
424 | local wasInRange = spec.isPlayerInRange |
425 | spec.isPlayerInRange, currentBelt = self:getIsPlayerInTensionBeltsRange() |
426 | if spec.isPlayerInRange then |
427 | if currentBelt ~= spec.currentBelt then |
428 | if spec.currentBelt ~= nil and spec.currentBelt.dummy ~= nil then |
429 | delete(spec.currentBelt.dummy) |
430 | spec.currentBelt.dummy = nil |
431 | end |
432 | spec.currentBelt = currentBelt |
433 | |
434 | if spec.currentBelt ~= nil and spec.currentBelt.mesh == nil then |
435 | local objects, _ = self:getObjectToMount(spec.currentBelt) |
436 | self:createTensionBelt(spec.currentBelt, true, objects) |
437 | end |
438 | end |
439 | g_currentMission:addActivatableObject(spec.activatable) |
440 | else |
441 | if wasInRange then |
442 | g_currentMission:removeActivatableObject(spec.activatable) |
443 | if spec.currentBelt ~= nil and spec.currentBelt.dummy ~= nil then |
444 | delete(spec.currentBelt.dummy) |
445 | spec.currentBelt.dummy = nil |
446 | spec.currentBelt = nil |
447 | end |
448 | end |
449 | end |
450 | end |
635 | function TensionBelts:setTensionBeltsActive(isActive, beltId, noEventSend) |
636 | local spec = self.spec_tensionBelts |
637 | |
638 | if spec.tensionBelts ~= nil then |
639 | TensionBeltsEvent.sendEvent(self, isActive, beltId, noEventSend) |
640 | |
641 | local belt = nil |
642 | if beltId ~= nil then |
643 | belt = spec.sortedBelts[beltId] |
644 | end |
645 | |
646 | if isActive then |
647 | local objects, _ = self:getObjectToMount(belt) |
648 | if belt == nil then |
649 | for _, belt in pairs(spec.singleBelts) do |
650 | if belt.mesh == nil then |
651 | self:createTensionBelt(belt, false, objects) |
652 | end |
653 | end |
654 | else |
655 | if belt.mesh == nil then |
656 | self:createTensionBelt(belt, false, objects) |
657 | end |
658 | end |
659 | |
660 | if self.isServer then |
661 | for _, data in pairs(objects) do |
662 | self:lockTensionBeltObject(data.physics, spec.objectsToJoint, spec.isDynamic, spec.jointNode, data.object) |
663 | if data.object ~= nil then |
664 | data.object.tensionMountObject = self |
665 | end |
666 | end |
667 | else |
668 | for _, data in pairs(objects) do |
669 | if data.object ~= nil then |
670 | data.object.tensionMountObject = self |
671 | end |
672 | end |
673 | end |
674 | else |
675 | if belt == nil then |
676 | for _, belt in pairs(spec.singleBelts) do |
677 | self:removeTensionBelt(belt) |
678 | end |
679 | else |
680 | self:removeTensionBelt(belt) |
681 | end |
682 | |
683 | if self.isServer then |
684 | -- remove joints |
685 | local objectIds, _ = self:getObjectsToUnmount(belt) |
686 | for _, objectId in pairs(objectIds) do |
687 | self:freeTensionBeltObject(objectId, spec.objectsToJoint, spec.isDynamic) |
688 | end |
689 | end |
690 | |
691 | local objects, _ = self:getObjectToMount(belt) |
692 | for _, data in pairs(objects) do |
693 | if data.object ~= nil then |
694 | data.object.tensionMountObject = nil |
695 | |
696 | if self.isServer then |
697 | if data.object.components ~= nil then |
698 | for _, component in ipairs(data.object.components) do |
699 | if component.node == data.physics then |
700 | component.isKinematic = false |
701 | component.isDynamic = true |
702 | end |
703 | end |
704 | end |
705 | end |
706 | end |
707 | end |
708 | end |
709 | |
710 | self:updateFastenState() |
711 | end |
712 | end |