21 | function LogGrab.initSpecialization() |
22 | local schema = Vehicle.xmlSchema |
23 | schema:setXMLSpecializationType("LogGrab") |
24 | |
25 | schema:register(XMLValueType.INT, "vehicle.logGrab.grab(?)#componentJoint", "Component joint index") |
26 | schema:register(XMLValueType.FLOAT, "vehicle.logGrab.grab(?)#dampingFactor", "Damping factor", 20) |
27 | schema:register(XMLValueType.INT, "vehicle.logGrab.grab(?)#axis", "Grab axis", 1) |
28 | schema:register(XMLValueType.ANGLE, "vehicle.logGrab.grab(?)#rotationOffsetThreshold", "Rotation offset threshold", 10) |
29 | schema:register(XMLValueType.FLOAT, "vehicle.logGrab.grab(?)#rotationOffsetTime", "Rotation offset time until mount", 1000) |
30 | |
31 | schema:register(XMLValueType.NODE_INDEX, "vehicle.logGrab#jointNode", "Joint node") |
32 | schema:register(XMLValueType.NODE_INDEX, "vehicle.logGrab#jointRoot", "Joint root node") |
33 | schema:register(XMLValueType.BOOL, "vehicle.logGrab#lockAllAxis", "Lock all axis", false) |
34 | schema:register(XMLValueType.NODE_INDEX, "vehicle.logGrab.trigger#node", "Trigger node") |
35 | |
36 | schema:setXMLSpecializationType() |
37 | end |
289 | function LogGrab:logGrabTriggerCallback(triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId) |
290 | local spec = self.spec_logGrab |
291 | |
292 | if onEnter then |
293 | if getSplitType(otherActorId) ~= 0 then |
294 | local rigidBodyType = getRigidBodyType(otherActorId) |
295 | if (rigidBodyType == RigidBodyType.DYNAMIC or rigidBodyType == RigidBodyType.KINEMATIC) and spec.pendingDynamicMountShapes[otherActorId] == nil then |
296 | spec.pendingDynamicMountShapes[otherActorId] = true |
297 | end |
298 | end |
299 | elseif onLeave then |
300 | if getSplitType(otherActorId) ~= 0 then |
301 | if spec.pendingDynamicMountShapes[otherActorId] ~= nil then |
302 | spec.pendingDynamicMountShapes[otherActorId] = nil |
303 | elseif spec.dynamicMountedShapes[otherActorId] ~= nil then |
304 | self:unmountSplitShape(otherActorId, spec.dynamicMountedShapes[otherActorId].jointIndex, spec.dynamicMountedShapes[otherActorId].jointTransform, true) |
305 | end |
306 | end |
307 | end |
308 | end |
244 | function LogGrab:mountSplitShape(shapeId) |
245 | local spec = self.spec_logGrab |
246 | |
247 | local constr = JointConstructor.new() |
248 | constr:setActors(spec.jointRoot, shapeId) |
249 | |
250 | local jointTransform = createTransformGroup("dynamicMountJoint") |
251 | link(spec.jointNode, jointTransform) |
252 | |
253 | constr:setJointTransforms(jointTransform, jointTransform) |
254 | |
255 | constr:setRotationLimit(0, 0, 0) |
256 | constr:setRotationLimit(1, 0, 0) |
257 | constr:setRotationLimit(2, 0, 0) |
258 | if not spec.lockAllAxis then |
259 | constr:setTranslationLimit(1, false, 0, 0) |
260 | constr:setTranslationLimit(2, false, 0, 0) |
261 | constr:setEnableCollision(true) |
262 | end |
263 | local springForce = 7500 |
264 | local springDamping = 1500 |
265 | constr:setRotationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping) |
266 | constr:setTranslationLimitSpring(springForce, springDamping, springForce, springDamping, springForce, springDamping) |
267 | |
268 | return constr:finalize(), jointTransform |
269 | end |
66 | function LogGrab:onLoad(savegame) |
67 | local spec = self.spec_logGrab |
68 | |
69 | if self.isServer then |
70 | spec.grabs = {} |
71 | |
72 | local i = 0 |
73 | while true do |
74 | local baseKey = string.format("vehicle.logGrab.grab(%d)", i) |
75 | if not self.xmlFile:hasProperty(baseKey) then |
76 | break |
77 | end |
78 | |
79 | local entry = {} |
80 | entry.componentJoint = self.xmlFile:getValue(baseKey.."#componentJoint") |
81 | entry.dampingFactor = self.xmlFile:getValue(baseKey.."#dampingFactor", 20) |
82 | entry.axis = self.xmlFile:getValue(baseKey.."#axis", 1) |
83 | entry.direction = {0, 0, 0} |
84 | entry.direction[entry.axis] = 1 |
85 | |
86 | local componentJoint = self.componentJoints[entry.componentJoint] |
87 | if componentJoint ~= nil then |
88 | entry.startRotDifference = {localDirectionToLocal(self.components[componentJoint.componentIndices[2]].node, componentJoint.jointNode, unpack(entry.direction))} |
89 | end |
90 | |
91 | entry.rotationOffsetThreshold = self.xmlFile:getValue(baseKey.."#rotationOffsetThreshold", 10) |
92 | entry.rotationOffsetTime = self.xmlFile:getValue(baseKey.."#rotationOffsetTime", 1000) |
93 | entry.rotationOffsetTimer = 0 |
94 | entry.rotationChangedTimer = 0 |
95 | entry.currentOffset = 0 |
96 | |
97 | table.insert(spec.grabs, entry) |
98 | i = i + 1 |
99 | end |
100 | |
101 | spec.jointNode = self.xmlFile:getValue("vehicle.logGrab#jointNode", nil, self.components, self.i3dMappings) |
102 | spec.jointRoot = self.xmlFile:getValue("vehicle.logGrab#jointRoot", nil, self.components, self.i3dMappings) |
103 | |
104 | spec.lockAllAxis = self.xmlFile:getValue("vehicle.logGrab#lockAllAxis", false) |
105 | |
106 | spec.triggerNode = self.xmlFile:getValue("vehicle.logGrab.trigger#node", nil, self.components, self.i3dMappings) |
107 | if spec.triggerNode ~= nil then |
108 | addTrigger(spec.triggerNode, "logGrabTriggerCallback", self) |
109 | end |
110 | |
111 | spec.pendingDynamicMountShapes = {} |
112 | spec.dynamicMountedShapes = {} |
113 | |
114 | spec.jointLimitsOpen = false |
115 | end |
116 | |
117 | if not self.isServer then |
118 | SpecializationUtil.removeEventListener(self, "onUpdateTick", LogGrab) |
119 | end |
120 | end |
134 | function LogGrab:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
135 | local spec = self.spec_logGrab |
136 | |
137 | local isGrabClosed = true |
138 | for _, grab in ipairs(spec.grabs) do |
139 | if not self:updateLogGrabState(grab, dt) then |
140 | isGrabClosed = false |
141 | end |
142 | end |
143 | |
144 | for shape,_ in pairs(spec.pendingDynamicMountShapes) do |
145 | if not entityExists(shape) then |
146 | spec.pendingDynamicMountShapes[shape] = nil |
147 | end |
148 | end |
149 | |
150 | if isGrabClosed then |
151 | for shape,_ in pairs(spec.pendingDynamicMountShapes) do |
152 | if spec.dynamicMountedShapes[shape] == nil then |
153 | local jointIndex, jointTransform = self:mountSplitShape(shape) |
154 | if jointIndex ~= nil then |
155 | spec.dynamicMountedShapes[shape] = {jointIndex=jointIndex, jointTransform=jointTransform} |
156 | spec.pendingDynamicMountShapes[shape] = nil |
157 | end |
158 | end |
159 | end |
160 | |
161 | if not spec.jointLimitsOpen and next(spec.dynamicMountedShapes) ~= nil then |
162 | spec.jointLimitsOpen = true |
163 | |
164 | for _, grab in ipairs(spec.grabs) do |
165 | local componentJoint = self.componentJoints[grab.componentJoint] |
166 | if componentJoint ~= nil then |
167 | for i=1, 3 do |
168 | setJointRotationLimitSpring(componentJoint.jointIndex, i-1, componentJoint.rotLimitSpring[i], componentJoint.rotLimitDamping[i]*grab.dampingFactor) |
169 | end |
170 | end |
171 | end |
172 | end |
173 | else |
174 | for shapeId, shapeData in pairs(spec.dynamicMountedShapes) do |
175 | self:unmountSplitShape(shapeId, shapeData.jointIndex, shapeData.jointTransform, false) |
176 | end |
177 | |
178 | if spec.jointLimitsOpen then |
179 | spec.jointLimitsOpen = false |
180 | |
181 | for _, grab in ipairs(spec.grabs) do |
182 | local componentJoint = self.componentJoints[grab.componentJoint] |
183 | if componentJoint ~= nil then |
184 | for i=1, 3 do |
185 | setJointRotationLimitSpring(componentJoint.jointIndex, i-1, componentJoint.rotLimitSpring[i], componentJoint.rotLimitDamping[i]) |
186 | end |
187 | end |
188 | end |
189 | end |
190 | end |
191 | end |
334 | function LogGrab:updateDebugValues(values) |
335 | local spec = self.spec_logGrab |
336 | |
337 | if self.isServer then |
338 | for i, grab in ipairs(spec.grabs) do |
339 | 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)}) |
340 | end |
341 | |
342 | for shapeId, _ in pairs(spec.dynamicMountedShapes) do |
343 | if entityExists(shapeId) then |
344 | table.insert(values, {name="mounted: ", value=tostring(getName(shapeId))}) |
345 | end |
346 | end |
347 | |
348 | for shapeId, _ in pairs(spec.pendingDynamicMountShapes) do |
349 | if entityExists(shapeId) then |
350 | table.insert(values, {name="pending: ", value=tostring(getName(shapeId))}) |
351 | end |
352 | end |
353 | end |
354 | end |
195 | function LogGrab:updateLogGrabState(grab, dt) |
196 | local componentJoint = self.componentJoints[grab.componentJoint] |
197 | if componentJoint ~= nil then |
198 | local start = grab.startRotDifference |
199 | local dirX, dirY, dirZ = localDirectionToLocal(self.components[componentJoint.componentIndices[2]].node, componentJoint.jointNode, unpack(grab.direction)) |
200 | |
201 | local currentOffset = 0 |
202 | if grab.axis == 1 then |
203 | currentOffset = start[1]-dirX |
204 | elseif grab.axis == 2 then |
205 | currentOffset = start[2]-dirY |
206 | elseif grab.axis == 3 then |
207 | currentOffset = start[3]-dirZ |
208 | end |
209 | |
210 | if math.abs(currentOffset) > grab.rotationOffsetThreshold then |
211 | if grab.rotationOffsetTimer > grab.rotationOffsetTime then |
212 | return true |
213 | else |
214 | grab.rotationOffsetTimer = grab.rotationOffsetTimer + dt |
215 | end |
216 | elseif grab.rotationOffsetTimer > 0 then |
217 | local x, y, z = getRotation(componentJoint.jointNode) |
218 | local rotSum = x + y + z |
219 | -- only unmount if the rotation of the componentJoint has changed -> if user opens the grab |
220 | if grab.lastRotation ~= nil and rotSum ~= grab.lastRotation then |
221 | grab.rotationOffsetTimer = 0 |
222 | grab.rotationChangedTimer = 750 |
223 | grab.lastRotation = nil |
224 | else |
225 | grab.rotationChangedTimer = math.max(grab.rotationChangedTimer - dt) |
226 | if grab.rotationChangedTimer <= 0 then |
227 | grab.lastRotation = rotSum |
228 | return true |
229 | else |
230 | grab.rotationOffsetTimer = 0 |
231 | grab.lastRotation = nil |
232 | end |
233 | end |
234 | end |
235 | |
236 | grab.currentOffset = currentOffset |
237 | end |
238 | |
239 | return false |
240 | end |