Sprache Deutsch Language English

Script Dokumentation LS 2015 - Cylindered (Patch 1.3)

Script Dokumentation Übersicht

scripts/vehicles/specializations/Cylindered.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1--
2-- Cylindered
3-- This is the specialization for vehicles which have movable parts
4--
5-- @author Stefan Geiger
6-- @date 18/08/09
7--
8-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
9
10Cylindered = {};
11
12g_cylinderedFix = true;
13
14function Cylindered.prerequisitesPresent(specializations)
15 --return SpecializationUtil.hasSpecialization(Steerable, specializations);
16 return true;
17end;
18
19function Cylindered:load(xmlFile)
20
21 self.setMovingToolDirty = SpecializationUtil.callSpecializationsFunction("setMovingToolDirty");
22 self.updateCylinderedInitial = SpecializationUtil.callSpecializationsFunction("updateCylinderedInitial");
23 self.isDetachAllowed = Utils.overwrittenFunction(self.isDetachAllowed, Cylindered.isDetachAllowed);
24
25 if self.isClient then
26 self.sampleCylinderedHydraulic = Utils.loadSample(xmlFile, {}, "vehicle.cylinderedHydraulicSound", nil, self.baseDirectory);
27 end;
28
29 self.activeDirtyMovingParts = {};
30
31 local referenceNodes = {};
32 self.nodesToMovingParts = {};
33 self.movingParts = {};
34 self.detachLockNodes = nil;
35 local i=0;
36 while true do
37 local baseName = string.format("vehicle.movingParts.movingPart(%d)", i);
38 if not hasXMLProperty(xmlFile, baseName) then
39 break;
40 end;
41
42 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.."#index"));
43 local referenceFrame = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.."#referenceFrame"));
44 if node ~= nil and referenceFrame ~= nil then
45 local entry = {};
46 entry.referencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.."#referencePoint"));
47 entry.node = node;
48 entry.referenceFrame = referenceFrame;
49 entry.invertZ = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#invertZ"), false);
50 entry.scaleZ = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#scaleZ"), false);
51 entry.limitedAxis = getXMLInt(xmlFile, baseName.."#limitedAxis");
52 local isActiveDirty = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#isActiveDirty"), false);
53 entry.playSound = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#playSound"), not isActiveDirty)
54
55 entry.moveToReferenceFrame = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#moveToReferenceFrame"), false);
56 if entry.moveToReferenceFrame then
57 local x,y,z = worldToLocal(referenceFrame, getWorldTranslation(node));
58 entry.referenceFrameOffset = {x,y,z};
59 end
60
61 entry.doDirectionAlignment = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#doDirectionAlignment"), true);
62
63 local minRot = getXMLFloat(xmlFile, baseName.."#minRot");
64 local maxRot = getXMLFloat(xmlFile, baseName.."#maxRot");
65 if minRot ~= nil and maxRot ~= nil then
66 if entry.limitedAxis ~= nil then
67 entry.minRot = Utils.getValidLimit(math.rad(minRot));
68 entry.maxRot = Utils.getValidLimit(math.rad(maxRot));
69 else
70 print("Warning: minRot/maxRot requires the use of limitedAxis in '"..self.configFileName.."'");
71 end;
72 end;
73 entry.alignToWorldY = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#alignToWorldY"), false);
74
75 if entry.referencePoint ~= nil then
76 local localReferencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.."#localReferencePoint"));
77 local refX, refY, refZ = worldToLocal(node, getWorldTranslation(entry.referencePoint));
78 if localReferencePoint ~= nil then
79 local x,y,z = worldToLocal(node, getWorldTranslation(localReferencePoint));
80
81 entry.referenceDistance = Utils.vector3Length(refX-x, refY-y, refZ-z);
82 entry.localReferencePoint = {x, y, z};
83
84 local side = y*(refZ-z) - z*(refY-y);
85 entry.localReferenceAngleSide = side;
86 entry.localReferencePointNode = localReferencePoint;
87 entry.updateLocalReferenceDistance = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#updateLocalReferenceDistance"), false);
88 else
89 entry.referenceDistance = 0;
90 entry.localReferencePoint = {refX, refY, refZ};
91 end;
92 entry.useLocalOffset = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#useLocalOffset"), false);
93
94 entry.localReferenceDistance = Utils.vector2Length(entry.localReferencePoint[2], entry.localReferencePoint[3]);
95
96 Cylindered.loadTranslatingParts(self, xmlFile, baseName, entry);
97
98 end
99 entry.isDirty = false;
100
101
102 if referenceNodes[node] == nil then
103 referenceNodes[node] = {};
104 end;
105 table.insert(referenceNodes[node], entry);
106
107 Cylindered.loadDependentParts(self, xmlFile, baseName, entry);
108
109 Cylindered.loadComponentJoints(self, xmlFile, baseName, entry);
110 Cylindered.loadAttacherJoints(self, xmlFile, baseName, entry);
111
112 Cylindered.loadCopyLocalDirectionParts(self, xmlFile, baseName, entry);
113
114 table.insert(self.movingParts, entry);
115
116 if isActiveDirty then
117 table.insert(self.activeDirtyMovingParts, entry);
118 end
119
120 self.nodesToMovingParts[node] = entry;
121 end;
122 i = i+1;
123 end;
124
125 self.isActiveDirtyTimeOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.movingParts#isActiveDirtyTimeOffset"), 0) * 1000;
126 self.isActiveDirtyTime = g_currentMission.time;
127
128 -- find dependencies
129 for _, part in pairs(self.movingParts) do
130 part.dependentParts = {};
131 for _, ref in pairs(part.dependentPartNodes) do
132 if referenceNodes[ref] ~= nil then
133 for _, p in pairs(referenceNodes[ref]) do
134 part.dependentParts[p] = p;
135 end;
136 end;
137 end;
138 end;
139
140
141 function hasDependentPart(w1, w2)
142 if w1.dependentParts[w2] ~= nil then
143 return true;
144 else
145 for _, v in pairs(w1.dependentParts) do
146 if hasDependentPart(v, w2) then
147 return true;
148 end;
149 end;
150 end;
151 return false;
152 end;
153
154 -- sort moving parts by dependencies
155 function movingPartsSort(w1,w2)
156 if hasDependentPart(w1, w2) then
157 return true;
158 end
159 if not hasDependentPart(w2, w1) then
160 return w1.node < w2.node;
161 end
162 return false;
163 end
164
165 table.sort(self.movingParts, movingPartsSort);
166
167 self.nodesToMovingTools = {};
168 self.movingTools = {};
169 local i=0;
170 while true do
171 local baseName = string.format("vehicle.movingTools.movingTool(%d)", i);
172 if not hasXMLProperty(xmlFile, baseName) then
173 break;
174 end;
175 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, baseName.."#index"));
176 if node ~= nil then
177 local entry = {};
178 entry.node = node;
179
180 entry.externalRotSpeed = 0;
181 entry.externalTransSpeed = 0;
182 -- rotation
183 local rotSpeed = getXMLFloat(xmlFile, baseName.."#rotSpeed");
184 if rotSpeed ~= nil then
185 entry.rotSpeed = math.rad(rotSpeed)/1000;
186 end;
187 local rotAcceleration = getXMLFloat(xmlFile, baseName.."#rotAcceleration");
188 if rotAcceleration ~= nil then
189 entry.rotAcceleration = math.rad(rotAcceleration)/(1000*1000);
190 end;
191 entry.lastRotSpeed = 0;
192 local rotMax = getXMLFloat(xmlFile, baseName.."#rotMax");
193 if rotMax ~= nil then
194 entry.rotMax = math.rad(rotMax);
195 end;
196 local rotMin = getXMLFloat(xmlFile, baseName.."#rotMin");
197 if rotMin ~= nil then
198 entry.rotMin = math.rad(rotMin);
199 end;
200 entry.syncMaxRotLimits = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#syncMaxRotLimits"), false);
201 entry.syncMinRotLimits = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#syncMinRotLimits"), false);
202 entry.rotSendNumBits = Utils.getNoNil(getXMLInt(xmlFile, baseName.."#rotSendNumBits"), 8);
203 local attachRotMax = getXMLFloat(xmlFile, baseName.."#attachRotMax");
204 if attachRotMax ~= nil then
205 entry.attachRotMax = math.rad(attachRotMax);
206 end;
207 local attachRotMin = getXMLFloat(xmlFile, baseName.."#attachRotMin");
208 if attachRotMin ~= nil then
209 entry.attachRotMin = math.rad(attachRotMin);
210 end;
211
212 -- translation
213 local transSpeed = getXMLFloat(xmlFile, baseName.."#transSpeed");
214 if transSpeed ~= nil then
215 entry.transSpeed = transSpeed/1000;
216 end;
217 local transAcceleration = getXMLFloat(xmlFile, baseName.."#transAcceleration");
218 if transAcceleration ~= nil then
219 entry.transAcceleration = transAcceleration/(1000*1000);
220 end;
221 entry.lastTransSpeed = 0;
222 entry.transMax = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#transMax"), 1);
223 entry.transMin = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#transMin"), 0);
224 entry.transSendNumBits = Utils.getNoNil(getXMLInt(xmlFile, baseName.."#transSendNumBits"), 8);
225 entry.attachTransMax = getXMLFloat(xmlFile, baseName.."#attachTransMax");
226 entry.attachTransMin = getXMLFloat(xmlFile, baseName.."#attachTransMin");
227
228 entry.axis = getXMLString(xmlFile, baseName.."#axis");
229 if entry.axis ~= nil then
230 entry.axisActionIndex = InputBinding[entry.axis];
231
232 if entry.axisActionIndex ~= nil then
233 self:addConflictCheckedInput(entry.axisActionIndex);
234 end
235 end
236 entry.invertAxis = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#invertAxis"), false);
237 entry.invertMouseAxis = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#invertMouseAxis"), false);
238 entry.speedFactor = Utils.getNoNil(getXMLFloat(xmlFile, baseName.."#speedFactor"), 1.0);
239 entry.isDirty = false;
240 entry.rotationAxis = Utils.getNoNil(getXMLInt(xmlFile, baseName.."#rotationAxis"), 1);
241 entry.translationAxis = Utils.getNoNil(getXMLInt(xmlFile, baseName.."#translationAxis"), 3);
242
243 entry.foldMinLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMinLimit"), 0);
244 entry.foldMaxLimit = Utils.getNoNil(getXMLFloat(xmlFile, baseName .. "#foldMaxLimit"), 1);
245
246 local detachingRotMaxLimit = getXMLFloat(xmlFile, baseName.."#detachingRotMaxLimit");
247 local detachingRotMinLimit = getXMLFloat(xmlFile, baseName.."#detachingRotMinLimit");
248 local detachingTransMaxLimit = getXMLFloat(xmlFile, baseName.."#detachingTransMaxLimit");
249 local detachingTransMinLimit = getXMLFloat(xmlFile, baseName.."#detachingTransMinLimit");
250 if detachingRotMaxLimit ~= nil or detachingRotMinLimit ~= nil or detachingTransMaxLimit ~= nil or detachingTransMinLimit ~= nil then
251 if self.detachLockNodes == nil then
252 self.detachLockNodes = {};
253 end;
254
255 local detachLock = {};
256 if detachingRotMaxLimit ~= nil then
257 detachLock.detachingRotMaxLimit = math.rad(detachingRotMaxLimit);
258 end;
259 if detachingRotMinLimit ~= nil then
260 detachLock.detachingRotMinLimit = math.rad(detachingRotMinLimit);
261 end;
262 detachLock.detachingTransMaxLimit = detachingTransMaxLimit;
263 detachLock.detachingTransMaxLimit = detachingTransMaxLimit;
264
265 self.detachLockNodes[entry] = detachLock;
266 end;
267
268
269 local x,y,z = getRotation(node);
270 entry.curRot = {x,y,z};
271 local x,y,z = getTranslation(node);
272 entry.curTrans = {x,y,z};
273
274 entry.startRot = getXMLFloat(xmlFile, baseName.."#startRot");
275 if entry.startRot ~= nil then
276 entry.startRot = math.rad(entry.startRot);
277 end;
278 entry.startTrans = getXMLFloat(xmlFile, baseName.."#startTrans");
279
280
281 entry.isDelayed = Utils.getNoNil(getXMLBool(xmlFile, baseName.."#isDelayed"), false);
282
283 if entry.isDelayed then
284 entry.history = {};
285 entry.history[1] = {move=0, moveDt=0};
286 entry.history[2] = {move=0, moveDt=0};
287 entry.history[3] = {move=0, moveDt=0};
288 end
289
290 entry.adjustAttributesToMovingToolIndex = getXMLInt(xmlFile, baseName.."#adjustAttributesToMovingToolIndex");
291
292 if referenceNodes[node] == nil then
293 referenceNodes[node] = {};
294 end;
295 table.insert(referenceNodes[node], entry);
296
297 local indices = Utils.getVectorNFromString(getXMLString(xmlFile, baseName.. "#wheelIndices"));
298 if indices ~= nil then
299 local wheels = {};
300 for _,wheelIndex in pairs(indices) do
301 local wheel = self.wheels[wheelIndex];
302 if wheel ~= nil then
303 table.insert(wheels, wheel);
304 else
305 print("Warning: Invalid wheelIndex '"..wheelIndex.."' in '"..self.configFileName.."'");
306 end;
307 end;
308 if table.getn(wheels) > 0 then
309 entry.wheels = wheels;
310 end;
311 end;
312
313 Cylindered.loadDependentMovingTools(self, xmlFile, baseName, entry);
314
315 Cylindered.loadDependentParts(self, xmlFile, baseName, entry);
316
317 Cylindered.loadComponentJoints(self, xmlFile, baseName, entry);
318 Cylindered.loadAttacherJoints(self, xmlFile, baseName, entry);
319
320 entry.isActive = true;
321 table.insert(self.movingTools, entry);
322 self.nodesToMovingTools[node] = entry;
323 end;
324 i = i+1;
325 end;
326
327 for _, part in pairs(self.movingTools) do
328 part.dependentParts = {};
329 for _, ref in pairs(part.dependentPartNodes) do
330 if referenceNodes[ref] ~= nil then
331 for _, p in pairs(referenceNodes[ref]) do
332 part.dependentParts[p] = p;
333 end;
334 end;
335 end;
336 for _, dependentTool in pairs(part.dependentMovingTools) do
337 dependentTool.movingTool = self.nodesToMovingTools[dependentTool.node];
338 end;
339 end;
340
341 for _, tool in pairs(self.movingTools) do
342 if tool.startRot ~= nil then
343 tool.curRot[tool.rotationAxis] = tool.startRot;
344 setRotation(tool.node, unpack(tool.curRot));
345 end;
346 if tool.startTrans ~= nil then
347 tool.curTrans[tool.translationAxis] = tool.startTrans;
348 setTranslation(tool.node, unpack(tool.curTrans));
349 end;
350 Cylindered.setDirty(self, tool);
351 end;
352
353 self.cylinderedDirtyFlag = self:getNextDirtyFlag();
354
355 for _, tool in pairs(self.movingTools) do
356 if (tool.rotSpeed ~= nil or tool.transSpeed ~= nil) and tool.axisActionIndex ~= nil then
357 self.isSelectable = true;
358 break;
359 end
360 end
361
362end;
363
364function Cylindered:delete()
365 if self.isClient then
366 Utils.deleteSample(self.sampleCylinderedHydraulic);
367 end;
368end;
369
370function Cylindered:readStream(streamId, connection)
371 for i=1, table.getn(self.movingTools) do
372 local tool = self.movingTools[i];
373 local changed = false;
374 if tool.transSpeed ~= nil then
375 local newTrans=streamReadFloat32(streamId);
376 if math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then
377 tool.curTrans[tool.translationAxis] = newTrans;
378 setTranslation(tool.node, unpack(tool.curTrans));
379 changed = true;
380 end;
381 end;
382 if tool.rotSpeed ~= nil then
383 local newRot=streamReadFloat32(streamId)
384 if math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then
385 tool.curRot[tool.rotationAxis] = newRot;
386 setRotation(tool.node, unpack(tool.curRot));
387 changed = true;
388 end;
389 end;
390 if changed then
391 Cylindered.setDirty(self, tool);
392 end;
393 end;
394end;
395
396function Cylindered:writeStream(streamId, connection)
397 for i=1, table.getn(self.movingTools) do
398 local tool = self.movingTools[i];
399 if tool.transSpeed ~= nil then
400 streamWriteFloat32(streamId, tool.curTrans[tool.translationAxis]);
401 end;
402 if tool.rotSpeed ~= nil then
403 streamWriteFloat32(streamId, tool.curRot[tool.rotationAxis]);
404 end;
405 end;
406end;
407
408function Cylindered:readUpdateStream(streamId, timestamp, connection)
409 local hasUpdate = streamReadBool(streamId);
410 if hasUpdate then
411 for i=1, table.getn(self.movingTools) do
412 local tool = self.movingTools[i];
413 if tool.axisActionIndex ~= nil then
414 local changed = false;
415 if tool.transSpeed ~= nil then
416 local newTrans=Utils.readCompressedRange(streamId, tool.transMin, tool.transMax, tool.transSendNumBits);
417 if math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then
418 tool.curTrans[tool.translationAxis] = newTrans;
419 setTranslation(tool.node, unpack(tool.curTrans));
420 changed = true;
421 end;
422 end;
423 if tool.rotSpeed ~= nil then
424 local newRot;
425 if tool.rotMin == nil or tool.rotMax == nil then
426 newRot = Utils.readCompressedAngle(streamId);
427 else
428 if tool.syncMinRotLimits then
429 tool.rotMin = streamReadFloat32(streamId);
430 end;
431 if tool.syncMaxRotLimits then
432 tool.rotMax = streamReadFloat32(streamId);
433 end;
434 newRot = Utils.readCompressedRange(streamId, tool.rotMin, tool.rotMax, tool.rotSendNumBits);
435 end;
436 if math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then
437 tool.curRot[tool.rotationAxis] = newRot;
438 setRotation(tool.node, unpack(tool.curRot));
439 changed = true;
440 end;
441 end;
442 if changed then
443 Cylindered.setDirty(self, tool);
444 end;
445 end
446 end;
447 if not connection:getIsServer() then
448 -- we are on the server, write the data to the clients
449 self:raiseDirtyFlags(self.cylinderedDirtyFlag);
450 end;
451 end;
452end;
453
454function Cylindered:writeUpdateStream(streamId, connection, dirtyMask)
455 if bitAND(dirtyMask, self.cylinderedDirtyFlag) ~= 0 and (connection:getIsServer() or connection ~= self:getOwner()) then
456 -- either we are on the client, or the target connection is not the owner
457 streamWriteBool(streamId, true);
458 for i=1, table.getn(self.movingTools) do
459 local tool = self.movingTools[i];
460 if tool.axisActionIndex ~= nil then
461 if tool.transSpeed ~= nil then
462 Utils.writeCompressedRange(streamId, tool.curTrans[tool.translationAxis], tool.transMin, tool.transMax, tool.transSendNumBits);
463 end;
464 if tool.rotSpeed ~= nil then
465 local rot = tool.curRot[tool.rotationAxis];
466 if tool.rotMin == nil or tool.rotMax == nil then
467 Utils.writeCompressedAngle(streamId, rot);
468 else
469 if tool.syncMinRotLimits then
470 streamWriteFloat32(streamId, tool.rotMin);
471 end;
472 if tool.syncMaxRotLimits then
473 streamWriteFloat32(streamId, tool.rotMax);
474 end;
475 Utils.writeCompressedRange(streamId, rot, tool.rotMin, tool.rotMax, tool.rotSendNumBits);
476 end;
477 end;
478 end
479 end;
480 else
481 streamWriteBool(streamId, false);
482 end;
483end;
484
485
486function Cylindered.loadDependentMovingTools(self, xmlFile, baseName, entry)
487 entry.dependentMovingTools = {};
488 local j=0;
489 while true do
490 local refBaseName = baseName..string.format(".dependentMovingTool(%d)", j);
491 if not hasXMLProperty(xmlFile, refBaseName) then
492 break;
493 end;
494 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index"));
495 local rotSpeedScale = getXMLFloat(xmlFile, refBaseName.."#rotSpeedScale");
496 local transSpeedScale = getXMLFloat(xmlFile, refBaseName.."#transSpeedScale");
497 local minTransLimits = getXMLString(xmlFile, refBaseName.."#minTransLimits")
498 local maxTransLimits = getXMLString(xmlFile, refBaseName.."#maxTransLimits")
499 local minRotLimits = getXMLString(xmlFile, refBaseName.."#minRotLimits")
500 local maxRotLimits = getXMLString(xmlFile, refBaseName.."#maxRotLimits")
501 if node ~= nil and (rotSpeedScale ~= nil or transSpeedScale ~= nil or minTransLimits ~= nil or maxTransLimits ~= nil or minRotLimits ~= nil or maxRotLimits ~= nil) then
502 local dependentTool = {};
503 dependentTool.node = node;
504 dependentTool.rotSpeedScale = rotSpeedScale;
505 dependentTool.transSpeedScale = transSpeedScale;
506 dependentTool.minTransLimits = Utils.getVectorNFromString(minTransLimits, 2);
507 dependentTool.maxTransLimits = Utils.getVectorNFromString(maxTransLimits, 2);
508 dependentTool.minRotLimits = Utils.getRadiansFromString(minRotLimits, 2);
509 dependentTool.maxRotLimits = Utils.getRadiansFromString(maxRotLimits, 2);
510 table.insert(entry.dependentMovingTools, dependentTool);
511 end;
512
513 j = j+1;
514 end;
515end;
516
517function Cylindered.loadDependentParts(self, xmlFile, baseName, entry)
518 entry.dependentPartNodes = {};
519 local j=0;
520 while true do
521 local refBaseName = baseName..string.format(".dependentPart(%d)", j);
522 if not hasXMLProperty(xmlFile, refBaseName) then
523 break;
524 end;
525 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index"));
526 if node ~= nil then
527 table.insert(entry.dependentPartNodes, node);
528 end;
529 j = j+1;
530 end;
531end;
532
533function Cylindered.loadComponentJoints(self, xmlFile, baseName, entry)
534 local indices = Utils.getVectorNFromString(getXMLString(xmlFile, baseName.. "#componentJointIndex"));
535 local actors = Utils.getNoNil(Utils.getVectorNFromString(getXMLString(xmlFile, baseName.. "#anchorActor")), {});
536 if indices ~= nil then
537 local componentJoints = {};
538 for i=1, table.getn(indices) do
539 local componentJoint = self.componentJoints[indices[i]+1];
540 if componentJoint ~= nil then
541 local anchorActor = Utils.getNoNil(actors[i], 0);
542 local jointEntry = {componentJoint=componentJoint, anchorActor=anchorActor };
543
544 local node = self.components[componentJoint.componentIndices[((anchorActor+1)%2)+1] ].node;
545 jointEntry.x,jointEntry.y,jointEntry.z = worldToLocal(componentJoint.jointNode, getWorldTranslation(node));
546 jointEntry.upX,jointEntry.upY,jointEntry.upZ = worldDirectionToLocal(componentJoint.jointNode, localDirectionToWorld(node, 0, 1, 0));
547 jointEntry.dirX,jointEntry.dirY,jointEntry.dirZ = worldDirectionToLocal(componentJoint.jointNode, localDirectionToWorld(node, 0, 0, 1));
548
549 table.insert(componentJoints, jointEntry );
550 end;
551 end;
552 if table.getn(componentJoints) > 0 then
553 entry.componentJoints = componentJoints;
554 end;
555 end;
556end;
557
558function Cylindered.loadAttacherJoints(self, xmlFile, baseName, entry)
559
560 local indices = Utils.getVectorNFromString(getXMLString(xmlFile, baseName.. "#attacherJointIndices"));
561 --local index = getXMLInt(xmlFile, baseName.. "#componentJointIndex");
562 if indices ~= nil then
563 local attacherJoints = {};
564 for i=1, table.getn(indices) do
565 local attacherJoint = self.attacherJoints[indices[i]+1];
566 if attacherJoint ~= nil then
567 table.insert(attacherJoints, attacherJoint);
568 end;
569 end;
570 if table.getn(attacherJoints) > 0 then
571 entry.attacherJoints = attacherJoints;
572 end;
573 end;
574 entry.inputAttacherJoint = Utils.getNoNil(getXMLBool(xmlFile, baseName.. "#inputAttacherJoint"), false);
575end;
576
577function Cylindered.loadTranslatingParts(self, xmlFile, baseName, entry)
578 entry.translatingParts = {};
579 if entry.referencePoint ~= nil then
580 local j=0;
581 while true do
582 local refBaseName = baseName..string.format(".translatingPart(%d)", j);
583 if not hasXMLProperty(xmlFile, refBaseName) then
584 break;
585 end;
586 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index"));
587 if node ~= nil then
588 local transEntry = {};
589 transEntry.node = node;
590 local x,y,z = getTranslation(node);
591 transEntry.startPos = {x,y,z};
592 local x,y,z = worldToLocal(node, getWorldTranslation(entry.referencePoint));
593 transEntry.referenceDistance = z;
594 transEntry.referenceDistancePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#referenceDistancePoint"));
595 table.insert(entry.translatingParts, transEntry);
596 end;
597 j = j+1;
598 end;
599 end
600end;
601
602function Cylindered.loadCopyLocalDirectionParts(self, xmlFile, baseName, entry)
603 entry.copyLocalDirectionParts = {};
604 local j=0;
605 while true do
606 local refBaseName = baseName..string.format(".copyLocalDirectionPart(%d)", j);
607 if not hasXMLProperty(xmlFile, refBaseName) then
608 break;
609 end;
610 local node = Utils.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#index"));
611 if node ~= nil then
612 local copyLocalDirectionPart = {};
613 copyLocalDirectionPart.node = node;
614 copyLocalDirectionPart.dirScale = Utils.getVectorNFromString(getXMLString(xmlFile, refBaseName.."#dirScale"), 3);
615 copyLocalDirectionPart.upScale = Utils.getVectorNFromString(getXMLString(xmlFile, refBaseName.."#upScale"), 3);
616
617 Cylindered.loadComponentJoints(self, xmlFile, refBaseName, copyLocalDirectionPart);
618
619 table.insert(entry.copyLocalDirectionParts, copyLocalDirectionPart);
620 end;
621 j = j + 1;
622 end;
623end;
624
625function Cylindered:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
626 if not resetVehicles then
627 for i, tool in ipairs(self.movingTools) do
628 if tool.axisActionIndex ~= nil then
629 local toolKey = key..string.format(".movingTool%d",i);
630 local changed = false;
631 if tool.transSpeed ~= nil then
632 local newTrans = getXMLFloat(xmlFile, toolKey.."#translation");
633 if newTrans ~= nil then
634 if tool.transMax ~= nil then
635 newTrans = math.min(newTrans, tool.transMax);
636 end;
637 if tool.transMin ~= nil then
638 newTrans = math.max(newTrans, tool.transMin);
639 end;
640 end
641 if newTrans ~= nil and math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then
642 tool.curTrans[tool.translationAxis] = newTrans;
643 setTranslation(tool.node, unpack(tool.curTrans));
644 changed = true;
645 end;
646 end;
647 if tool.rotSpeed ~= nil then
648 local newRot = getXMLFloat(xmlFile, toolKey.."#rotation");
649 if newRot ~= nil then
650 if tool.rotMax ~= nil then
651 newRot = math.min(newRot, tool.rotMax);
652 end;
653 if tool.rotMin ~= nil then
654 newRot = math.max(newRot, tool.rotMin);
655 end;
656 end
657 if newRot ~= nil and math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then
658 tool.curRot[tool.rotationAxis] = newRot;
659 setRotation(tool.node, unpack(tool.curRot));
660 changed = true;
661 end;
662 end;
663 if changed then
664 Cylindered.setDirty(self, tool);
665 end;
666 end
667 end
668 -- cycle again to match delayed mesh and physics tools
669 for i, tool in ipairs(self.movingTools) do
670 if tool.axisActionIndex ~= nil then
671 local toolKey = key..string.format(".movingTool%d",i);
672 if tool.adjustAttributesToMovingToolIndex ~= nil then
673 if self.movingTools[tool.adjustAttributesToMovingToolIndex] ~= nil then
674 local changed = false;
675 if tool.transSpeed ~= nil then
676 local newTrans = self.movingTools[tool.adjustAttributesToMovingToolIndex].curTrans[tool.translationAxis];
677 tool.curTrans[tool.translationAxis] = newTrans;
678 setTranslation(tool.node, unpack(tool.curTrans));
679 elseif tool.rotSpeed ~= nil then
680 local newRot = self.movingTools[tool.adjustAttributesToMovingToolIndex].curRot[tool.rotationAxis];
681 tool.curRot[tool.rotationAxis] = newRot;
682 setRotation(tool.node, unpack(tool.curRot));
683 end;
684 Cylindered.setDirty(self, tool);
685 end;
686 end;
687 end;
688 end;
689
690 self:updateCylinderedInitial(false);
691 end
692 return BaseMission.VEHICLE_LOAD_OK;
693end;
694
695function Cylindered:getSaveAttributesAndNodes(nodeIdent)
696 local attributes = "";
697 local nodes = "";
698 local numNodes = 0;
699 for i, tool in ipairs(self.movingTools) do
700 if tool.axisActionIndex ~= nil and (tool.transSpeed ~= nil or tool.rotSpeed ~= nil) then
701 if numNodes > 0 then
702 nodes = nodes.."\n";
703 end
704 numNodes = numNodes + 1;
705
706 nodes = nodes.. nodeIdent..string.format('<movingTool%d', i);
707 if tool.transSpeed ~= nil then
708 nodes = nodes.. ' translation="'..tool.curTrans[tool.translationAxis]..'"';
709 end
710 if tool.rotSpeed ~= nil then
711 nodes = nodes.. ' rotation="'..tool.curRot[tool.rotationAxis]..'"';
712 end
713 nodes = nodes..'/>';
714 end
715 end
716
717 return attributes, nodes;
718end;
719
720function Cylindered:mouseEvent(posX, posY, isDown, isUp, button)
721end;
722
723function Cylindered:keyEvent(unicode, sym, modifier, isDown)
724end;
725
726function Cylindered:update(dt)
727 if self:getIsActive() then
728 if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then
729
730 local foldAnimTime = self.foldAnimTime;
731 for i=1, table.getn(self.movingTools) do
732 local tool = self.movingTools[i];
733 local foldActive = (foldAnimTime == nil or (foldAnimTime <= tool.foldMaxLimit and foldAnimTime >= tool.foldMinLimit));
734 if tool.isActive and foldActive and (tool.rotSpeed ~= nil or tool.transSpeed ~= nil) and tool.axisActionIndex ~= nil then
735 local move, axisType = InputBinding.getInputAxis(tool.axisActionIndex);
736 if axisType == InputBinding.INPUTTYPE_MOUSE_AXIS then
737 if tool.invertMouseAxis then
738 move = -move;
739 end
740 if InputBinding.actions[tool.axisActionIndex].mouseAxis == InputBinding.MOUSE_AXIS_Y then
741 move = move * InputBinding.yDirection;
742 end;
743 move = move * tool.speedFactor;
744 else
745 if tool.invertAxis then
746 move = -move;
747 end
748 if InputBinding.actions[tool.axisActionIndex].gamepadAxis == Input.AXIS_4 then
749 move = move * InputBinding.yDirection;
750 end;
751 end
752
753 local moveDt = dt;
754
755 if tool.isDelayed then
756 tool.history[1] = tool.history[2];
757 tool.history[2] = tool.history[3];
758 tool.history[3] = {move=move, moveDt=dt};
759
760 move = tool.history[1].move;
761 moveDt = tool.history[1].moveDt;
762 end;
763 local isAxisZero = InputBinding.isAxisZero(move);
764
765 local rotSpeed = 0;
766 local transSpeed = 0;
767 if not isAxisZero then
768 if tool.rotSpeed ~= nil then
769 rotSpeed = move*tool.rotSpeed;
770 if tool.rotAcceleration ~= nil and math.abs(rotSpeed - tool.lastRotSpeed) >= tool.rotAcceleration*moveDt then
771 if rotSpeed > tool.lastRotSpeed then
772 rotSpeed = tool.lastRotSpeed + tool.rotAcceleration*moveDt;
773 else
774 rotSpeed = tool.lastRotSpeed - tool.rotAcceleration*moveDt;
775 end;
776 end;
777 end;
778 if tool.transSpeed ~= nil then
779 transSpeed = move*tool.transSpeed;
780 if tool.transAcceleration ~= nil and math.abs(transSpeed - tool.lastTransSpeed) >= tool.transAcceleration*moveDt then
781 if transSpeed > tool.lastTransSpeed then
782 transSpeed = tool.lastTransSpeed + tool.transAcceleration*moveDt;
783 else
784 transSpeed = tool.lastTransSpeed - tool.transAcceleration*moveDt;
785 end;
786 end;
787 end;
788 else
789 -- decelerate
790 if tool.externalRotSpeed ~= 0 then
791 rotSpeed = tool.externalRotSpeed;
792 elseif tool.rotAcceleration ~= nil then
793 if tool.lastRotSpeed < 0 then
794 rotSpeed = math.min(tool.lastRotSpeed + tool.rotAcceleration*moveDt, 0);
795 else
796 rotSpeed = math.max(tool.lastRotSpeed - tool.rotAcceleration*moveDt, 0);
797 end;
798 end;
799 if tool.externalTransSpeed ~= 0 then
800 transSpeed = tool.externalTransSpeed;
801 elseif tool.transAcceleration ~= nil then
802 if tool.lastTransSpeed < 0 then
803 transSpeed = math.min(tool.lastTransSpeed + tool.transAcceleration*moveDt, 0);
804 else
805 transSpeed = math.max(tool.lastTransSpeed - tool.transAcceleration*moveDt, 0);
806 end;
807 end;
808 end;
809
810 local changed = false;
811 if rotSpeed ~= 0 then
812 changed = changed or Cylindered.setToolRotation(self, tool, rotSpeed, moveDt);
813 else
814 tool.lastRotSpeed = 0;
815 end;
816 if transSpeed ~= 0 then
817 changed = changed or Cylindered.setToolTranslation(self, tool, transSpeed, moveDt);
818 else
819 tool.lastTransSpeed = 0;
820 end;
821
822 for _, dependentTool in pairs(tool.dependentMovingTools) do
823 if dependentTool.rotSpeedScale ~= nil and tool.lastRotSpeed ~= 0 then
824 dependentTool.movingTool.externalRotSpeed = dependentTool.rotSpeedScale * tool.lastRotSpeed;
825 end
826 if dependentTool.transSpeedScale ~= nil and tool.lastTransSpeed ~= 0 then
827 dependentTool.movingTool.externalTransSpeed = dependentTool.transSpeedScale * tool.lastTransSpeed;
828 end
829 if dependentTool.minTransLimits ~= nil or dependentTool.maxTransLimits ~= nil then
830
831 local state = Cylindered.getMovingToolState(self, tool);
832 if dependentTool.minTransLimits ~= nil then
833 dependentTool.movingTool.transMin = Utils.lerp(dependentTool.minTransLimits[1], dependentTool.minTransLimits[2], 1-state);
834 end;
835 if dependentTool.maxTransLimits ~= nil then
836 dependentTool.movingTool.transMax = Utils.lerp(dependentTool.maxTransLimits[1], dependentTool.maxTransLimits[2], 1-state);
837 end;
838 local transLimitChanged = Cylindered.setToolTranslation(self, dependentTool.movingTool, 0, 0);
839 if transLimitChanged then
840 Cylindered.setDirty(self, dependentTool.movingTool);
841 end;
842 end;
843 if dependentTool.minRotLimits ~= nil or dependentTool.maxRotLimits ~= nil then
844
845 local state = Cylindered.getMovingToolState(self, tool);
846 if dependentTool.minRotLimits ~= nil then
847 dependentTool.movingTool.rotMin = Utils.lerp(dependentTool.minRotLimits[1], dependentTool.minRotLimits[2], 1-state);
848 end;
849 if dependentTool.maxRotLimits ~= nil then
850 dependentTool.movingTool.rotMax = Utils.lerp(dependentTool.maxRotLimits[1], dependentTool.maxRotLimits[2], 1-state);
851 end;
852 local rotLimitChanged = Cylindered.setToolRotation(self, dependentTool.movingTool, 0, 0);
853 if rotLimitChanged then
854 Cylindered.setDirty(self, dependentTool.movingTool);
855 end;
856 end;
857 end;
858
859 if changed then
860 Cylindered.setDirty(self, tool);
861 self:raiseDirtyFlags(self.cylinderedDirtyFlag);
862 end;
863 end;
864 tool.externalRotSpeed = 0;
865 tool.externalTransSpeed = 0;
866 end;
867 end;
868
869 self.isActiveDirtyTime = g_currentMission.time + self.isActiveDirtyTimeOffset;
870 end
871
872 if self.isActiveDirtyTime >= g_currentMission.time then
873 for _, part in pairs(self.activeDirtyMovingParts) do
874 Cylindered.setDirty(self, part);
875 end
876 end;
877
878 for _, tool in pairs(self.movingTools) do
879 if tool.isDirty then
880 if self.isServer then
881 -- update component joint
882 Cylindered.updateComponentJoints(self, tool, false);
883 end;
884
885 tool.isDirty = false;
886 end;
887 end;
888
889 for i, part in ipairs(self.movingParts) do
890 if part.isDirty then
891 Cylindered.updateMovingPart(self, part, false);
892 if self.isClient and part.playSound and not self.sampleCylinderedHydraulic.isPlaying and self:getIsActiveForSound() then
893 self.cylinderedHydraulicSoundPartNumber = i;
894 Utils.playSample(self.sampleCylinderedHydraulic, 0, 0, nil);
895 end;
896 else
897 if self.isClient and self.cylinderedHydraulicSoundPartNumber == i then
898 Utils.stopSample(self.sampleCylinderedHydraulic);
899 end;
900 end;
901 end;
902end;
903
904function Cylindered:updateTick(dt)
905end;
906
907function Cylindered:draw()
908end;
909
910function Cylindered.setToolTranslation(self, tool, transSpeed, dt)
911 local newTrans = tool.curTrans[tool.translationAxis]+transSpeed*dt;
912 if tool.transMax ~= nil then
913 newTrans = math.min(newTrans, tool.transMax);
914 end;
915 if tool.transMin ~= nil then
916 newTrans = math.max(newTrans, tool.transMin);
917 end;
918 local diff = newTrans - tool.curTrans[tool.translationAxis];
919 if dt ~= 0 then
920 tool.lastTransSpeed = diff/dt;
921 end;
922 if math.abs(diff) > 0.0001 then
923 tool.curTrans[tool.translationAxis] = newTrans;
924 setTranslation(tool.node, unpack(tool.curTrans));
925 return true;
926 end;
927
928 return false;
929end;
930
931function Cylindered.setToolRotation(self, tool, rotSpeed, dt)
932 local newRot = tool.curRot[tool.rotationAxis]+rotSpeed*dt;
933
934 if tool.rotMax ~= nil then
935 newRot = math.min(newRot, tool.rotMax);
936 end
937 if tool.rotMin ~= nil then
938 newRot = math.max(newRot, tool.rotMin);
939 end
940 local diff = newRot - tool.curRot[tool.rotationAxis];
941 if dt ~= 0 then
942 tool.lastRotSpeed = diff/dt;
943 end;
944 if math.abs(diff) > 0.0001 then
945 -- wrap if not limited
946 if tool.rotMin == nil and tool.rotMax == nil then
947 if newRot > 2*math.pi then
948 newRot = newRot - 2*math.pi;
949 end;
950 if newRot < 0 then
951 newRot = newRot + 2*math.pi;
952 end;
953 end
954 tool.curRot[tool.rotationAxis] = newRot;
955 setRotation(tool.node, unpack(tool.curRot));
956 return true;
957 end;
958
959 return false;
960end;
961
962function Cylindered.getMovingToolState(self, tool)
963 local state = 0;
964 if tool.rotMax ~= nil and tool.rotMin ~= nil then
965 state = (tool.curRot[tool.rotationAxis]-tool.rotMin) / (tool.rotMax-tool.rotMin);
966 else
967 if tool.transMax ~= nil and tool.transMin ~= nil then
968 state = (tool.curTrans[tool.translationAxis]-tool.transMin) / (tool.transMax-tool.transMin);
969 end;
970 end;
971
972 return state;
973end;
974
975function Cylindered:setMovingToolDirty(node)
976 local tool = self.nodesToMovingTools[node];
977 if tool ~= nil then
978 local x,y,z = getRotation(tool.node);
979 tool.curRot[1] = x;
980 tool.curRot[2] = y;
981 tool.curRot[3] = z;
982 local x,y,z = getTranslation(tool.node);
983 tool.curTrans[1] = x;
984 tool.curTrans[2] = y;
985 tool.curTrans[3] = z;
986 Cylindered.setDirty(self, tool);
987 end;
988end;
989
990function Cylindered.setDirty(self, part)
991 if not part.isDirty then
992 part.isDirty = true;
993
994 Cylindered.updateAttacherJoints(self, part);
995
996 if part.wheels ~= nil then
997 for _, wheel in pairs(part.wheels) do
998 wheel.positionX, wheel.positionY, wheel.positionZ = localToLocal(getParent(wheel.repr), wheel.node, wheel.startPositionX, wheel.startPositionY, wheel.startPositionZ);
999 self:updateWheelBase(wheel);
1000 end;
1001 end;
1002
1003 for _, v in pairs(part.dependentParts) do
1004 Cylindered.setDirty(self, v);
1005 end;
1006 end;
1007end;
1008
1009function Cylindered.updateMovingPart(self, part, placeComponents)
1010
1011 -- the local reference point must be referenceDistance away from the referencePoint
1012 local refX,refY,refZ;
1013 local dirX, dirY, dirZ = 0,0,0;
1014 if part.referencePoint ~= nil then
1015 if part.moveToReferenceFrame then
1016 local x,y,z = localToLocal(part.referenceFrame, getParent(part.node), part.referenceFrameOffset[1], part.referenceFrameOffset[2], part.referenceFrameOffset[3]);
1017 setTranslation(part.node, x,y,z);
1018 end
1019 refX,refY,refZ = getWorldTranslation(part.referencePoint);
1020 if part.referenceDistance == 0 then
1021 if part.useLocalOffset then
1022 local lx, ly, lz = worldToLocal(part.node, refX, refY, refZ);
1023 dirX, dirY, dirZ = localDirectionToWorld(part.node, lx-part.localReferencePoint[1], ly-part.localReferencePoint[2], lz);
1024 else
1025 local x,y,z = getWorldTranslation(part.node);
1026 dirX, dirY, dirZ = refX - x, refY-y, refZ-z;
1027 end
1028 else
1029 if part.updateLocalReferenceDistance then
1030 local _,y,z = worldToLocal(part.node, getWorldTranslation(part.localReferencePointNode));
1031 part.localReferenceDistance = Utils.vector2Length(y, z);
1032 end;
1033 if part.referenceDistancePoint ~= nil then
1034 local _,_,z = worldToLocal(part.node, getWorldTranslation(part.referenceDistancePoint));
1035 part.referenceDistance = z;
1036 end;
1037
1038 local r1 = part.localReferenceDistance;
1039 local r2 = part.referenceDistance;
1040 local lx, ly, lz = worldToLocal(part.node, refX, refY, refZ);
1041 --print("intersect: "..ly .. " "..lz);
1042 local ix, iy, i2x, i2y = Utils.getCircleCircleIntersection(0,0, r1, ly, lz, r2);
1043
1044 if ix ~= nil then
1045 if i2x ~= nil then
1046 -- use the point which as the same angle side as the original configuration
1047 local side = ix*(lz-iy) - iy*(ly-ix);
1048 if (side < 0) ~= (part.localReferenceAngleSide < 0) then
1049 iy = i2y;
1050 ix = i2x;
1051 end
1052 end
1053 dirX, dirY, dirZ = localDirectionToWorld(part.node, 0, ix, iy)
1054 end;
1055 end;
1056 else
1057 if part.alignToWorldY then
1058 dirX, dirY, dirZ = localDirectionToWorld(getRootNode(), 0, 1, 0);
1059 else
1060 dirX, dirY, dirZ = localDirectionToWorld(part.referenceFrame, 0, 0, 1);
1061 end;
1062 if part.moveToReferenceFrame then
1063 local x,y,z = localToLocal(part.referenceFrame, getParent(part.node), part.referenceFrameOffset[1], part.referenceFrameOffset[2], part.referenceFrameOffset[3]);
1064 setTranslation(part.node, x,y,z);
1065 end
1066 end
1067 if (dirX ~= 0 or dirY ~= 0 or dirZ ~= 0) and part.doDirectionAlignment then
1068 local upX, upY, upZ = localDirectionToWorld(part.referenceFrame, 0, 1, 0);
1069 if part.invertZ then
1070 dirX = -dirX;
1071 dirY = -dirY;
1072 dirZ = -dirZ;
1073 end;
1074
1075 -- just debugging to get more info for this error message:
1076 -- ... fabsf(Vector3::dotProduct(direction, up)) < 0.9999f*direction.calcMagnitude()*up.calcMagnitude()
1077 if GS_PLATFORM_TYPE == GS_PLATFORM_TYPE_PC and part.printedBadReferenceFrameMessage ~= true and g_isDevelopmentVersion then
1078 local parent = getParent(part.node);
1079
1080 local dirX2,dirY2,dirZ2 = worldDirectionToLocal(parent, dirX,dirY,dirZ);
1081 local upX2,upY2,upZ2 = worldDirectionToLocal(parent, upX,upY,upZ);
1082
1083 local dotProd = math.abs( (dirX2*upX2 + dirY2*upY2 + dirZ2*upZ2) );
1084
1085 if dotProd > 0.9999 * (Utils.vector3Length(dirX2,dirY2,dirZ2) * Utils.vector3Length(upX2,upY2,upZ2)) then
1086 print("Error: Node '" .. getName(part.node) .. "' has a bad reference frame! ("..self.configFileName..")");
1087 part.printedBadReferenceFrameMessage = true;
1088 end;
1089 end;
1090 -- end debugging
1091
1092 Utils.setWorldDirection(part.node, dirX, dirY, dirZ, upX, upY, upZ, part.limitedAxis, part.minRot, part.maxRot);
1093
1094 if part.scaleZ and part.localReferenceDistance ~= nil then
1095 local len = Utils.vector3Length(dirX, dirY, dirZ);
1096 setScale(part.node, 1, 1, len/part.localReferenceDistance);
1097 end
1098 end
1099
1100 if part.referencePoint ~= nil then
1101 local numTranslatingParts = table.getn(part.translatingParts)
1102 if numTranslatingParts > 0 then
1103 local _, _, dist = worldToLocal(part.node, refX, refY, refZ);
1104 for i=1,numTranslatingParts do
1105 local translatingPart = part.translatingParts[i];
1106 local newZ = (dist - translatingPart.referenceDistance)/numTranslatingParts;
1107 setTranslation(translatingPart.node, translatingPart.startPos[1], translatingPart.startPos[2], newZ);
1108 end
1109 end
1110 end
1111
1112 if part.copyLocalDirectionParts ~= nil then
1113 for _,copyLocalDirectionPart in pairs(part.copyLocalDirectionParts) do
1114 local dx,dy,dz = localDirectionToWorld(part.node, 0,0,1);
1115 dx,dy,dz = worldDirectionToLocal(getParent(part.node), dx,dy,dz);
1116 dx = dx * copyLocalDirectionPart.dirScale[1];
1117 dy = dy * copyLocalDirectionPart.dirScale[2];
1118 dz = dz * copyLocalDirectionPart.dirScale[3];
1119
1120 local ux,uy,uz = localDirectionToWorld(part.node, 0,1,0);
1121 ux,uy,uz = worldDirectionToLocal(getParent(part.node), ux,uy,uz);
1122 ux = ux * copyLocalDirectionPart.upScale[1];
1123 uy = uy * copyLocalDirectionPart.upScale[2];
1124 uz = uz * copyLocalDirectionPart.upScale[3];
1125
1126 setDirection(copyLocalDirectionPart.node, dx,dy,dz, ux,uy,uz);
1127
1128 if self.isServer then
1129 Cylindered.updateComponentJoints(self, copyLocalDirectionPart, placeComponents);
1130 end;
1131 end;
1132 end;
1133
1134 -- update component joint
1135 if self.isServer then
1136 Cylindered.updateComponentJoints(self, part, placeComponents);
1137 Cylindered.updateAttacherJoints(self, part);
1138 end
1139
1140 part.isDirty = false;
1141end;
1142
1143function Cylindered.updateComponentJoints(self, entry, placeComponents)
1144 if self.isServer then
1145 if entry.componentJoints ~= nil then
1146 for _,joint in ipairs(entry.componentJoints) do
1147 local componentJoint = joint.componentJoint;
1148
1149 local jointNode = componentJoint.jointNode;
1150 if joint.anchorActor == 1 then
1151 jointNode = componentJoint.jointNodeActor1;
1152 end
1153 if placeComponents then
1154
1155 local node = self.components[componentJoint.componentIndices[((joint.anchorActor+1)%2)+1] ].node;
1156 local x,y,z = localToWorld(jointNode, joint.x, joint.y, joint.z);
1157 local upX,upY,upZ = localDirectionToWorld(jointNode, joint.upX,joint.upY,joint.upZ);
1158 local dirX,dirY,dirZ = localDirectionToWorld(jointNode, joint.dirX,joint.dirY,joint.dirZ);
1159 Utils.setWorldTranslation(node, x,y,z);
1160 Utils.setWorldDirection(node, dirX,dirY,dirZ, upX,upY,upZ);
1161 end
1162 setJointFrame(componentJoint.jointIndex, joint.anchorActor, jointNode);
1163 end;
1164 end;
1165 end;
1166end;
1167
1168function Cylindered.updateAttacherJoints(self, entry)
1169 if self.isServer then
1170 if entry.attacherJoints ~= nil then
1171 for _,joint in ipairs(entry.attacherJoints) do
1172 if joint.jointIndex ~= 0 then
1173 setJointFrame(joint.jointIndex, 0, joint.jointTransform);
1174 end;
1175 end;
1176 end;
1177 if entry.inputAttacherJoint and self.attacherVehicle ~= nil then
1178 local implement = self.attacherVehicle:getImplementByObject(self);
1179 if implement ~= nil then
1180 local jointDesc = self.attacherVehicle.attacherJoints[implement.jointDescIndex];
1181 if jointDesc.jointIndex ~= 0 then
1182 setJointFrame(jointDesc.jointIndex, 1, self.attacherJoint.node);
1183 end
1184 end
1185 end
1186 end;
1187end;
1188
1189function Cylindered:updateCylinderedInitial(placeComponents)
1190 if placeComponents == nil then
1191 placeComponents = true;
1192 end
1193
1194 for _, part in pairs(self.activeDirtyMovingParts) do
1195 Cylindered.setDirty(self, part);
1196 end
1197
1198 for _, tool in ipairs(self.movingTools) do
1199 if tool.isDirty then
1200 if self.isServer then
1201 Cylindered.updateComponentJoints(self, tool, placeComponents);
1202 end;
1203 tool.isDirty = false;
1204 end;
1205 end;
1206
1207 for _, part in ipairs(self.movingParts) do
1208 if part.isDirty then
1209 Cylindered.updateMovingPart(self, part, placeComponents);
1210 part.isDirty = false;
1211 end
1212 end
1213end
1214
1215function Cylindered:onAttach(attacherVehicle)
1216 for i, tool in ipairs(self.movingTools) do
1217 local changed = false;
1218 if tool.transSpeed ~= nil then
1219 local trans = tool.curTrans[tool.translationAxis];
1220
1221 local changedTrans = false;
1222 if tool.attachTransMax ~= nil and trans > tool.attachTransMax then
1223 trans = tool.attachTransMax;
1224 changedTrans = true;
1225 elseif tool.attachTransMin ~= nil and trans < tool.attachTransMin then
1226 trans = tool.attachTransMin;
1227 changedTrans = true;
1228 end;
1229 if changedTrans then
1230 tool.curTrans[tool.translationAxis] = trans;
1231 setTranslation(tool.node, unpack(tool.curTrans));
1232 changed = true;
1233 end;
1234 end;
1235 if tool.rotSpeed ~= nil then
1236 local rot = tool.curRot[tool.rotationAxis];
1237
1238 local changedRot = false;
1239 if tool.attachRotMax ~= nil and rot > tool.attachRotMax then
1240 rot = tool.attachRotMax;
1241 changedRot = true;
1242 elseif tool.attachRotMin ~= nil and rot < tool.attachRotMin then
1243 rot = tool.attachRotMin;
1244 changedRot = true;
1245 end;
1246 if changedRot then
1247 tool.curRot[tool.rotationAxis] = rot;
1248 setRotation(tool.node, unpack(tool.curRot));
1249 changed = true;
1250 end;
1251 end;
1252 if changed then
1253 Cylindered.setDirty(self, tool);
1254 end;
1255 end;
1256end;
1257
1258function Cylindered:onDeactivateSounds()
1259 if self.isClient then
1260 Utils.stopSample(self.sampleCylinderedHydraulic, true);
1261 end;
1262end;
1263
1264function Cylindered:isDetachAllowed(superFunc)
1265 if self.detachLockNodes ~= nil then
1266 for entry, data in pairs(self.detachLockNodes) do
1267 local node = entry.node;
1268 local rot = {getRotation(node)};
1269
1270 if data.detachingRotMinLimit ~= nil and rot[entry.rotationAxis] < data.detachingRotMinLimit then
1271 return false;
1272 end;
1273 if data.detachingRotMaxLimit ~= nil and rot[entry.rotationAxis] > data.detachingRotMaxLimit then
1274 return false;
1275 end;
1276
1277 local trans = {getTranslation(node)};
1278 if data.detachingTransMinLimit ~= nil and trans[entry.translationAxis] < data.detachingTransMinLimit then
1279 return false;
1280 end;
1281 if data.detachingTransMaxLimit ~= nil and trans[entry.translationAxis] > data.detachingTransMaxLimit then
1282 return false;
1283 end;
1284 end;
1285 end;
1286
1287 if superFunc ~= nil then
1288 return superFunc(self);
1289 end
1290 return true;
1291end;
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
Script Dokumentation Übersicht