261 | function LogGrab:logGrabTriggerCallback(triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId) |
262 | local spec = self.spec_logGrab |
263 | |
264 | if onEnter then |
265 | if getSplitType(otherActorId) ~= 0 then |
266 | local rigidBodyType = getRigidBodyType(otherActorId) |
267 | if (rigidBodyType == "Dynamic" or rigidBodyType == "Kinematic") and spec.pendingDynamicMountShapes[otherActorId] == nil then |
268 | spec.pendingDynamicMountShapes[otherActorId] = true |
269 | end |
270 | end |
271 | elseif onLeave then |
272 | if getSplitType(otherActorId) ~= 0 then |
273 | if spec.pendingDynamicMountShapes[otherActorId] ~= nil then |
274 | spec.pendingDynamicMountShapes[otherActorId] = nil |
275 | elseif spec.dynamicMountedShapes[otherActorId] ~= nil then |
276 | self:unmountSplitShape(otherActorId, spec.dynamicMountedShapes[otherActorId].jointIndex, spec.dynamicMountedShapes[otherActorId].jointTransform, true) |
277 | end |
278 | end |
279 | end |
280 | end |
216 | function LogGrab:mountSplitShape(shapeId) |
217 | local spec = self.spec_logGrab |
218 | |
219 | local constr = JointConstructor:new() |
220 | constr:setActors(spec.jointRoot, shapeId) |
221 | |
222 | local jointTransform = createTransformGroup("dynamicMountJoint") |
223 | link(spec.jointNode, jointTransform) |
224 | |
225 | constr:setJointTransforms(jointTransform, jointTransform) |
226 | |
227 | constr:setRotationLimit(0, 0, 0) |
228 | constr:setRotationLimit(1, 0, 0) |
229 | constr:setRotationLimit(2, 0, 0) |
230 | if not spec.lockAllAxis then |
231 | constr:setTranslationLimit(1, false, 0, 0) |
232 | constr:setTranslationLimit(2, false, 0, 0) |
233 | constr:setEnableCollision(true) |
234 | end |
235 | local springForce = 7500 |
236 | local springDamping = 1500 |
237 | constr:setRotationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping) |
238 | constr:setTranslationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping) |
239 | |
240 | return constr:finalize(), jointTransform |
241 | end |
46 | function LogGrab:onLoad(savegame) |
47 | local spec = self.spec_logGrab |
48 | |
49 | if self.isServer then |
50 | spec.grabs = {} |
51 | |
52 | local i = 0 |
53 | while true do |
54 | local baseKey = string.format("%s.grab(%d)", "vehicle.logGrab", i) |
55 | if not hasXMLProperty(self.xmlFile, baseKey) then |
56 | break |
57 | end |
58 | |
59 | local entry = {} |
60 | entry.componentJoint = getXMLInt(self.xmlFile, baseKey.."#componentJoint") |
61 | entry.dampingFactor = getXMLFloat(self.xmlFile, baseKey.."#dampingFactor") or 20 |
62 | entry.axis = getXMLInt(self.xmlFile, baseKey.."#axis") or 1 |
63 | entry.direction = {0, 0, 0} |
64 | entry.direction[entry.axis] = 1 |
65 | |
66 | local componentJoint = self.componentJoints[entry.componentJoint] |
67 | if componentJoint ~= nil then |
68 | entry.startRotDifference = {localDirectionToLocal(self.components[componentJoint.componentIndices[2]].node, componentJoint.jointNode, unpack(entry.direction))} |
69 | end |
70 | |
71 | entry.rotationOffsetThreshold = Utils.getNoNilRad(getXMLFloat(self.xmlFile, baseKey.."#rotationOffsetThreshold"), math.rad(10)) |
72 | entry.rotationOffsetTime = Utils.getNoNil(getXMLFloat(self.xmlFile, baseKey.."#rotationOffsetTime"), 1000) |
73 | entry.rotationOffsetTimer = 0 |
74 | entry.currentOffset = 0 |
75 | |
76 | table.insert(spec.grabs, entry) |
77 | i = i + 1 |
78 | end |
79 | |
80 | spec.jointNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logGrab#jointNode"), self.i3dMappings) |
81 | spec.jointRoot = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logGrab#jointRoot"), self.i3dMappings) |
82 | |
83 | spec.lockAllAxis = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.logGrab#lockAllAxis"), false) |
84 | |
85 | spec.triggerNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logGrab.trigger#node"), self.i3dMappings) |
86 | if spec.triggerNode ~= nil then |
87 | addTrigger(spec.triggerNode, "logGrabTriggerCallback", self) |
88 | end |
89 | |
90 | spec.pendingDynamicMountShapes = {} |
91 | spec.dynamicMountedShapes = {} |
92 | |
93 | spec.jointLimitsOpen = false |
94 | end |
95 | end |
111 | function LogGrab:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
112 | if self.isServer then |
113 | local spec = self.spec_logGrab |
114 | |
115 | local isGrabClosed = true |
116 | for _, grab in ipairs(spec.grabs) do |
117 | if not self:updateLogGrabState(grab, dt) then |
118 | isGrabClosed = false |
119 | end |
120 | end |
121 | |
122 | for shape,_ in pairs(spec.pendingDynamicMountShapes) do |
123 | if not entityExists(shape) then |
124 | spec.pendingDynamicMountShapes[shape] = nil |
125 | end |
126 | end |
127 | |
128 | if isGrabClosed then |
129 | for shape,_ in pairs(spec.pendingDynamicMountShapes) do |
130 | if spec.dynamicMountedShapes[shape] == nil then |
131 | local jointIndex, jointTransform = self:mountSplitShape(shape) |
132 | if jointIndex ~= nil then |
133 | spec.dynamicMountedShapes[shape] = {jointIndex=jointIndex, jointTransform=jointTransform} |
134 | spec.pendingDynamicMountShapes[shape] = nil |
135 | end |
136 | end |
137 | end |
138 | |
139 | if not spec.jointLimitsOpen and next(spec.dynamicMountedShapes) ~= nil then |
140 | spec.jointLimitsOpen = true |
141 | |
142 | for _, grab in ipairs(spec.grabs) do |
143 | local componentJoint = self.componentJoints[grab.componentJoint] |
144 | if componentJoint ~= nil then |
145 | for i=1, 3 do |
146 | setJointRotationLimitSpring(componentJoint.jointIndex, i-1, componentJoint.rotLimitSpring[i], componentJoint.rotLimitDamping[i]*grab.dampingFactor) |
147 | end |
148 | end |
149 | end |
150 | end |
151 | else |
152 | for shapeId, shapeData in pairs(spec.dynamicMountedShapes) do |
153 | self:unmountSplitShape(shapeId, shapeData.jointIndex, shapeData.jointTransform, false) |
154 | end |
155 | |
156 | if spec.jointLimitsOpen then |
157 | spec.jointLimitsOpen = false |
158 | |
159 | for _, grab in ipairs(spec.grabs) do |
160 | local componentJoint = self.componentJoints[grab.componentJoint] |
161 | if componentJoint ~= nil then |
162 | for i=1, 3 do |
163 | setJointRotationLimitSpring(componentJoint.jointIndex, i-1, componentJoint.rotLimitSpring[i], componentJoint.rotLimitDamping[i]) |
164 | end |
165 | end |
166 | end |
167 | end |
168 | end |
169 | end |
170 | end |
306 | function LogGrab:updateDebugValues(values) |
307 | local spec = self.spec_logGrab |
308 | |
309 | for i, grab in ipairs(spec.grabs) do |
310 | table.insert(values, {name=string.format("grab (%d):", i), value=string.format("current: %.2fdeg / threshold: %.2fdeg (timer: %d)", math.deg(math.abs(grab.currentOffset)), math.deg(grab.rotationOffsetThreshold), grab.rotationOffsetTimer)}) |
311 | end |
312 | |
313 | for shapeId, _ in pairs(spec.dynamicMountedShapes) do |
314 | table.insert(values, {name="mounted: ", value=tostring(getName(shapeId))}) |
315 | end |
316 | |
317 | for shapeId, _ in pairs(spec.pendingDynamicMountShapes) do |
318 | table.insert(values, {name="pending: ", value=tostring(getName(shapeId))}) |
319 | end |
320 | end |
174 | function LogGrab:updateLogGrabState(grab, dt) |
175 | local componentJoint = self.componentJoints[grab.componentJoint] |
176 | if componentJoint ~= nil then |
177 | local start = grab.startRotDifference |
178 | local dirX, dirY, dirZ = localDirectionToLocal(self.components[componentJoint.componentIndices[2]].node, componentJoint.jointNode, unpack(grab.direction)) |
179 | |
180 | local currentOffset = 0 |
181 | if grab.axis == 1 then |
182 | currentOffset = start[1]-dirX |
183 | elseif grab.axis == 2 then |
184 | currentOffset = start[2]-dirY |
185 | elseif grab.axis == 3 then |
186 | currentOffset = start[3]-dirZ |
187 | end |
188 | |
189 | if math.abs(currentOffset) > grab.rotationOffsetThreshold then |
190 | if grab.rotationOffsetTimer > grab.rotationOffsetTime then |
191 | return true |
192 | else |
193 | grab.rotationOffsetTimer = grab.rotationOffsetTimer + dt |
194 | end |
195 | elseif grab.rotationOffsetTimer > 0 then |
196 | local x, y, z = getRotation(componentJoint.jointNode) |
197 | local rotSum = x + y + z |
198 | -- only unmount if the rotation of the componentJoint has changed -> if user opens the grab |
199 | if grab.lastRotation ~= nil and rotSum ~= grab.lastRotation then |
200 | grab.rotationOffsetTimer = 0 |
201 | grab.lastRotation = nil |
202 | else |
203 | grab.lastRotation = rotSum |
204 | return true |
205 | end |
206 | end |
207 | |
208 | grab.currentOffset = currentOffset |
209 | end |
210 | |
211 | return false |
212 | end |