32 | function ArticulatedAxis:onLoad(savegame) |
33 | local xmlFile = self.xmlFile |
34 | local spec = self.spec_articulatedAxis |
35 | |
36 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.articulatedAxis.rotatingPart(0)#index", "vehicle.articulatedAxis.rotatingPart(0)#node") -- FS17 |
37 | |
38 | local index = getXMLInt(xmlFile, "vehicle.articulatedAxis#componentJointIndex") |
39 | if index ~= nil then |
40 | if index == 0 then |
41 | g_logManager:xmlWarning(self.configFileName, "Invalid component joint index '0' for articulatedAxis. Indices start with 1!") |
42 | else |
43 | local componentJoint = self.componentJoints[index] |
44 | local rotSpeed = getXMLFloat(xmlFile, "vehicle.articulatedAxis#rotSpeed") |
45 | local rotMax = getXMLFloat(xmlFile, "vehicle.articulatedAxis#rotMax") |
46 | local rotMin = getXMLFloat(xmlFile, "vehicle.articulatedAxis#rotMin") |
47 | if componentJoint ~= nil and rotSpeed ~= nil and rotMax ~= nil and rotMin ~= nil then |
48 | spec.rotSpeed = math.rad(rotSpeed) |
49 | spec.rotMax = math.rad(rotMax) |
50 | spec.rotMin = math.rad(rotMin) |
51 | |
52 | spec.componentJoint = componentJoint |
53 | spec.anchorActor = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.articulatedAxis#anchorActor"), 0) |
54 | spec.rotationNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, "vehicle.articulatedAxis#rotNode"), self.i3dMappings) |
55 | if spec.rotationNode == nil then |
56 | spec.rotationNode = spec.componentJoint.jointNode |
57 | end |
58 | |
59 | spec.curRot = 0 |
60 | |
61 | local i = 0 |
62 | spec.rotatingParts = {} |
63 | while true do |
64 | local key = string.format("vehicle.articulatedAxis.rotatingPart(%d)", i) |
65 | if not hasXMLProperty(xmlFile, key) then |
66 | break |
67 | end |
68 | |
69 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#node"), self.i3dMappings) |
70 | if node ~= nil then |
71 | local rotatingPart = {} |
72 | rotatingPart.node = node |
73 | rotatingPart.defRot = {getRotation(node)} |
74 | rotatingPart.posRot = StringUtil.getRadiansFromString(getXMLString(xmlFile, key .. "#posRot"), 3) |
75 | rotatingPart.negRot = StringUtil.getRadiansFromString(getXMLString(xmlFile, key .. "#negRot"), 3) |
76 | rotatingPart.negRotFactor = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#negRotFactor"), 1) |
77 | rotatingPart.posRotFactor = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#posRotFactor"), 1) |
78 | rotatingPart.invertSteeringAngle = Utils.getNoNil(getXMLBool(xmlFile, key .. "#invertSteeringAngle"), false) |
79 | table.insert(spec.rotatingParts, rotatingPart) |
80 | else |
81 | g_logManager:xmlWarning(self.configFileName, "Failed to load rotation part '%s'", key) |
82 | end |
83 | i = i + 1 |
84 | end |
85 | |
86 | -- adjust steering values |
87 | local maxRotTime = rotMax/rotSpeed |
88 | local minRotTime = rotMin/rotSpeed |
89 | if minRotTime > maxRotTime then |
90 | local temp = minRotTime |
91 | minRotTime = maxRotTime |
92 | maxRotTime = temp |
93 | end |
94 | if maxRotTime > self.maxRotTime then |
95 | self.maxRotTime = maxRotTime |
96 | end |
97 | if minRotTime < self.minRotTime then |
98 | self.minRotTime = minRotTime |
99 | end |
100 | |
101 | self.maxRotation = rotMax |
102 | self.wheelSteeringDuration = MathUtil.sign(rotSpeed) * rotMax / rotSpeed |
103 | |
104 | -- adjust variables used by AIVehicleUtil |
105 | local aiReverserNodeString = getXMLString(xmlFile, "vehicle.articulatedAxis#aiRevereserNode") |
106 | if aiReverserNodeString ~= nil then |
107 | spec.aiRevereserNode = I3DUtil.indexToObject(self.components, aiReverserNodeString, self.i3dMappings) |
108 | end |
109 | |
110 | local maxTurningRadius = 0 |
111 | local specWheels = self.spec_wheels |
112 | for i=1,2 do |
113 | local rootNode = self.components[componentJoint.componentIndices[i]].node |
114 | |
115 | for _, wheel in ipairs(specWheels.wheels) do |
116 | if self:getParentComponent(wheel.repr) == rootNode then |
117 | |
118 | local wx,_,wz = localToLocal(wheel.driveNode, rootNode, 0,0,0) |
119 | local dx1 = 1 |
120 | if wx < 0 then |
121 | dx1 = -1 |
122 | end |
123 | local dz1 = math.tan( math.max(wheel.rotMin, wheel.rotMax) ) |
124 | if wz > 0 then |
125 | dz1 = -dz1 |
126 | end |
127 | |
128 | local x2, z2 = 0, 0 |
129 | local dx2 = 1 |
130 | if wx < 0 then |
131 | dx2 = -1 |
132 | end |
133 | local dz2 = math.tan( math.max(rotMin, rotMax) ) |
134 | if wz < 0 then |
135 | dz2 = -dz2 |
136 | end |
137 | |
138 | -- normalize directions |
139 | local l1 = MathUtil.vector2Length(dx1, dz1) |
140 | dx1, dz1 = dx1 / l1, dz1 / l1 |
141 | |
142 | local l2 = MathUtil.vector2Length(dx2, dz2) |
143 | dx2, dz2 = dx2 / l2, dz2 / l2 |
144 | |
145 | local intersect, _, f2 = MathUtil.getLineLineIntersection2D(wx,wz, dx1,dz1, x2,z2, dx2,dz2) |
146 | if intersect then |
147 | local radius = math.abs(f2) |
148 | maxTurningRadius = math.max(maxTurningRadius, radius) |
149 | end |
150 | end |
151 | end |
152 | end |
153 | |
154 | if maxTurningRadius ~= 0 then |
155 | self.maxTurningRadius = maxTurningRadius |
156 | end |
157 | end |
158 | end |
159 | end |
160 | |
161 | spec.interpolatedRotatedTime = 0 |
162 | end |
180 | function ArticulatedAxis:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
181 | local spec = self.spec_articulatedAxis |
182 | if spec.componentJoint ~= nil then |
183 | -- interpolatedRotatedTime to manipulate camera rot |
184 | if spec.interpolatedRotatedTime < self.rotatedTime then |
185 | spec.interpolatedRotatedTime = math.min(self.rotatedTime, spec.interpolatedRotatedTime + math.abs(spec.rotSpeed) * dt/500) |
186 | elseif spec.interpolatedRotatedTime > self.rotatedTime then |
187 | spec.interpolatedRotatedTime = math.max(self.rotatedTime, spec.interpolatedRotatedTime - math.abs(spec.rotSpeed) * dt/500) |
188 | end |
189 | |
190 | local steeringAngle = MathUtil.clamp(self.rotatedTime * spec.rotSpeed, spec.rotMin, spec.rotMax) |
191 | if self.updateArticulatedAxisRotation ~= nil then |
192 | steeringAngle = self:updateArticulatedAxisRotation(steeringAngle, dt) |
193 | end |
194 | |
195 | if math.abs(steeringAngle - spec.curRot) > 0.000001 then |
196 | if self.isServer then |
197 | setRotation(spec.rotationNode, 0, steeringAngle, 0) |
198 | self:setComponentJointFrame(spec.componentJoint, spec.anchorActor) |
199 | spec.curRot = steeringAngle |
200 | end |
201 | |
202 | if self.isClient then |
203 | local percent = 0 |
204 | if steeringAngle > 0 then |
205 | percent = steeringAngle / spec.rotMax |
206 | elseif steeringAngle < 0 then |
207 | percent = steeringAngle / spec.rotMin |
208 | end |
209 | |
210 | for _,rotPart in pairs(spec.rotatingParts) do |
211 | local rx,ry,rz |
212 | if (steeringAngle > 0 and not rotPart.invertSteeringAngle) or (steeringAngle < 0 and rotPart.invertSteeringAngle) then |
213 | rx,ry,rz = MathUtil.vector3ArrayLerp(rotPart.defRot, rotPart.posRot, math.min(1,percent*rotPart.posRotFactor)) |
214 | else |
215 | rx,ry,rz = MathUtil.vector3ArrayLerp(rotPart.defRot, rotPart.negRot, math.min(1,percent*rotPart.negRotFactor)) |
216 | end |
217 | setRotation(rotPart.node, rx,ry,rz) |
218 | if self.setMovingToolDirty ~= nil then |
219 | self:setMovingToolDirty(rotPart.node) |
220 | end |
221 | end |
222 | end |
223 | end |
224 | end |
225 | end |