478 | function InlineBale:addBale(bale, baleType) |
479 | local success = false |
480 | if self.isServer then |
481 | if self.pendingBale == nil then |
482 | if self:getIsBaleAllowed(bale, baleType) then |
483 | table.insert(self.bales, bale) |
484 | self.pendingBale = bale |
485 | |
486 | self.wrappingState = self.wrappingState / #self.bales * (#self.bales - 1) |
487 | |
488 | if bale:isa(InlineBaleSingle) then |
489 | bale:setConnectedInlineBale(self) |
490 | end |
491 | |
492 | bale:addDeleteListener(self, "onBaleDeleted") |
493 | |
494 | self:raiseActive() |
495 | |
496 | success = true |
497 | end |
498 | end |
499 | else |
500 | table.insert(self.bales, bale) |
501 | |
502 | if bale:isa(InlineBaleSingle) then |
503 | bale:setConnectedInlineBale(self) |
504 | end |
505 | |
506 | success = true |
507 | end |
508 | |
509 | if success then |
510 | if bale.inlineWrapperToAdd ~= nil then |
511 | self:setCurrentWrapperInfo(bale.inlineWrapperToAdd.wrapper, bale.inlineWrapperToAdd.wrappingNode) |
512 | |
513 | bale.inlineWrapperToAdd = nil |
514 | end |
515 | end |
516 | |
517 | return success |
518 | end |
609 | function InlineBale:createBaleJoint(bale1, bale2) |
610 | local constr = JointConstructor.new() |
611 | constr:setActors(bale1.nodeId, bale2.nodeId) |
612 | constr:setJointTransforms(bale1.nodeId, bale2.nodeId) |
613 | constr:setEnableCollision(true) |
614 | |
615 | constr:setRotationLimit(0, -self.startRotLimit[1], self.startRotLimit[1]) |
616 | constr:setRotationLimit(1, -self.startRotLimit[2], self.startRotLimit[2]) |
617 | constr:setRotationLimit(2, -self.startRotLimit[3], self.startRotLimit[3]) |
618 | |
619 | constr:setTranslationLimit(0, true, -self.startTransLimit[1], self.startTransLimit[1]) |
620 | constr:setTranslationLimit(1, true, -self.startTransLimit[2], self.startTransLimit[2]) |
621 | constr:setTranslationLimit(2, true, -self.startTransLimit[3], self.startTransLimit[3]) |
622 | |
623 | local jointIndex = constr:finalize() |
624 | |
625 | local entry = {} |
626 | entry.jointIndex = jointIndex |
627 | entry.time = 0 |
628 | |
629 | self.baleJoints[bale1] = entry |
630 | end |
732 | function InlineBale:getCanInteract() |
733 | if #self.bales <= 0 then |
734 | return false |
735 | end |
736 | |
737 | if self.currentWrapper ~= nil then |
738 | return false |
739 | end |
740 | |
741 | local x1, y1, z1 = self:getInteractionPosition() |
742 | if x1 ~= nil then |
743 | local firstBale = self.bales[1] |
744 | local x2, y2, z2 = getWorldTranslation(firstBale.nodeId) |
745 | local distance = MathUtil.vector3Length(x1-x2, y1-y2, z1-z2) |
746 | |
747 | if distance < self.maxOpenDistance then |
748 | return true |
749 | end |
750 | |
751 | local lastBale = self.bales[#self.bales] |
752 | x2, y2, z2 = getWorldTranslation(lastBale.nodeId) |
753 | distance = MathUtil.vector3Length(x1-x2, y1-y2, z1-z2) |
754 | |
755 | if distance < self.maxOpenDistance then |
756 | return true |
757 | end |
758 | end |
759 | |
760 | return false |
761 | end |
117 | function InlineBale:loadFromConfigXML(configFileName) |
118 | self.configFileName = configFileName |
119 | |
120 | local _, baseDirectory = Utils.getModNameAndBaseDirectory(configFileName) |
121 | self.baseDirectory = baseDirectory |
122 | |
123 | local xmlFile = XMLFile.load("inlineBaleXml", configFileName, InlineBale.xmlSchema) |
124 | if xmlFile ~= nil then |
125 | self.maxOpenDistance = xmlFile:getValue("inlineBale#maxOpenDistance", self.maxOpenDistance) |
126 | |
127 | self.connectorFilename = Utils.getFilename(xmlFile:getValue("inlineBale.connector#filename"), self.baseDirectory) |
128 | self.connectorAxis = xmlFile:getValue("inlineBale.connector#axis", self.connectorAxis) |
129 | self.connectorOffset = xmlFile:getValue("inlineBale.connector#offset", self.connectorOffset) |
130 | |
131 | local replacementBaleFilename = xmlFile:getValue("inlineBale.replacementBale#filename") |
132 | if replacementBaleFilename ~= nil then |
133 | self.replacementBaleFilename = Utils.getFilename(replacementBaleFilename, self.baseDirectory) |
134 | if not fileExists(self.replacementBaleFilename) then |
135 | Logging.xmlWarning(xmlFile, "Unknown wrapper bale file '%s'", tostring(self.replacementBaleFilename)) |
136 | return false |
137 | end |
138 | end |
139 | |
140 | self.wrapDiffuse = Utils.getFilename(xmlFile:getValue("inlineBale.textures#diffuse"), self.baseDirectory) |
141 | if self.wrapDiffuse == nil or not fileExists(self.wrapDiffuse) then |
142 | Logging.xmlWarning(xmlFile, "Missing wrap diffuse '%s'", tostring(self.wrapDiffuse)) |
143 | return false |
144 | end |
145 | |
146 | self.wrapNormal = Utils.getFilename(xmlFile:getValue("inlineBale.textures#normal"), self.baseDirectory) |
147 | if self.wrapNormal == nil or not fileExists(self.wrapNormal) then |
148 | Logging.xmlWarning(xmlFile, "Missing wrap normal '%s'", tostring(self.wrapNormal)) |
149 | return false |
150 | end |
151 | |
152 | self.wrappingStateCurve = AnimCurve.new(linearInterpolator1) |
153 | local j = 0 |
154 | while true do |
155 | local key2 = string.format("inlineBale.wrapping.key(%d)", j) |
156 | if not xmlFile:hasProperty(key2) then |
157 | break |
158 | end |
159 | |
160 | local t = xmlFile:getValue(key2.."#time") |
161 | local wrappingState = xmlFile:getValue(key2.."#wrappingState") |
162 | |
163 | self.wrappingStateCurve:addKeyframe({wrappingState, time = t}) |
164 | j = j + 1 |
165 | end |
166 | |
167 | self.startRotLimit = xmlFile:getValue("inlineBale.joint#startRotLimit", self.startRotLimit, true) |
168 | self.endRotLimit = xmlFile:getValue("inlineBale.joint#endRotLimit", self.endRotLimit, true) |
169 | self.startTransLimit = xmlFile:getValue("inlineBale.joint#startTransLimit", self.startTransLimit, true) |
170 | self.endTransLimit = xmlFile:getValue("inlineBale.joint#endTransLimit", self.endTransLimit, true) |
171 | |
172 | self.wrappingAxis = xmlFile:getValue("inlineBale.joint#wrappingAxis", self.wrappingAxis) |
173 | self.wrappingAxisScale = {0, 0, 0} |
174 | self.wrappingAxisScale[math.abs(self.wrappingAxis)] = MathUtil.clamp(self.wrappingAxis, -1, 1) |
175 | |
176 | self.lockTime = xmlFile:getValue("inlineBale.joint#lockTime", self.lockTime / 1000) |
177 | |
178 | xmlFile:delete() |
179 | else |
180 | Logging.error("Unable to create InlineBale from config file '%s'", configFileName) |
181 | return false |
182 | end |
183 | |
184 | return true |
185 | end |
193 | function InlineBale:loadFromXMLFile(xmlFile, key) |
194 | self.configFileName = xmlFile:getValue(key .. "#filename") |
195 | if self.configFileName == nil then |
196 | Logging.error("Unable to load InlineBale from savegame. No filename given.") |
197 | return false |
198 | end |
199 | |
200 | if not self:loadFromConfigXML(self.configFileName) then |
201 | Logging.error("Unable to load InlineBale from savegame.") |
202 | return false |
203 | end |
204 | |
205 | local i = 0 |
206 | while true do |
207 | local baseKey = string.format("%s.bales.bale(%d)", key, i) |
208 | if not xmlFile:hasProperty(baseKey) then |
209 | break |
210 | end |
211 | |
212 | local entry = {} |
213 | entry.saveId = xmlFile:getValue(baseKey.."#saveId") |
214 | if entry.saveId ~= nil then |
215 | table.insert(self.balesToLoad, entry) |
216 | end |
217 | |
218 | i = i + 1 |
219 | end |
220 | |
221 | if #self.balesToLoad > 0 then |
222 | self:raiseActive() |
223 | else |
224 | self.removeEmptyInlineBale = true |
225 | self:raiseActive() |
226 | end |
227 | |
228 | self.numBalesSent = 0 |
229 | |
230 | return true |
231 | end |
61 | function InlineBale.new(isServer, isClient, customMt) |
62 | local self = Object.new(isServer, isClient, customMt or InlineBale_mt) |
63 | |
64 | self.bales = {} |
65 | self.baleJoints = {} |
66 | self.pendingBale = nil |
67 | self.wrappingColor = {1, 1, 1, 1} |
68 | self.wrappingState = 0 |
69 | |
70 | self.configFileName = nil |
71 | |
72 | self.maxOpenDistance = 3 |
73 | |
74 | self.connector = nil |
75 | self.connectorAxis = 1 |
76 | self.connectorOffset = 0.5 |
77 | |
78 | self.wrappingStateCurve = nil |
79 | |
80 | self.startRotLimit = {0, 0, 0} |
81 | self.endRotLimit = {0, 0, 0} |
82 | self.startTransLimit = {0, 0, 0} |
83 | self.endTransLimit = {0, 0, 0} |
84 | |
85 | self.wrappingAxis = 1 |
86 | self.wrappingAxisScale = {1, 0, 0} |
87 | self.lockTime = 5000 |
88 | |
89 | self.balesToLoad = {} |
90 | |
91 | registerObjectClassName(self, "InlineBale") |
92 | g_currentMission.itemSystem:addItemToSave(self) |
93 | |
94 | self.activatable = InlineBaleActivatable.new(self) |
95 | self.balesDirtyFlag = self:getNextDirtyFlag() |
96 | self.wrapperDirtyFlag = self:getNextDirtyFlag() |
97 | |
98 | self.wakeUpDelay = 0 |
99 | |
100 | return self |
101 | end |
878 | function InlineBale:onBaleDeleted(bale) |
879 | if self.pendingBale == nil then |
880 | if self.bales[1] == bale then |
881 | self:openBale(bale, true, false) |
882 | elseif self.bales[#self.bales] == bale then |
883 | self:openBale(bale, false, false) |
884 | else |
885 | local baleIndex |
886 | for i, bale2 in ipairs(self.bales) do |
887 | if bale2 == bale then |
888 | baleIndex = i |
889 | end |
890 | end |
891 | |
892 | if baleIndex ~= nil then |
893 | if baleIndex > #self.bales - baleIndex then |
894 | -- remove all bales from behind until we reach the deleted bale |
895 | for i=#self.bales, baleIndex + 1, -1 do |
896 | self:openBale(self.bales[i], false) |
897 | end |
898 | |
899 | self:openBale(bale, false, false) |
900 | else |
901 | -- remove all bales from the start until we reach the deleted bale |
902 | for i=1, baleIndex - 1 do |
903 | self:openBale(self.bales[1], true) |
904 | end |
905 | |
906 | self:openBale(bale, true, false) |
907 | end |
908 | end |
909 | end |
910 | end |
911 | end |
814 | function InlineBale:openBale(bale, isFirst, replaceBale) |
815 | if isFirst then |
816 | -- remove connector |
817 | local nextBale = self.bales[2] |
818 | self:removeBaleConnector(nextBale) |
819 | |
820 | -- remove joint |
821 | local joint = self.baleJoints[bale] |
822 | if joint ~= nil then |
823 | removeJoint(joint.jointIndex) |
824 | end |
825 | |
826 | -- reorder bales |
827 | for i=1, #self.bales - 1 do |
828 | self.bales[i] = self.bales[i+1] |
829 | end |
830 | else |
831 | -- remove connector |
832 | self:removeBaleConnector(bale) |
833 | |
834 | -- remove joint |
835 | local prevBale = self.bales[#self.bales-1] |
836 | if prevBale ~= nil then |
837 | local joint = self.baleJoints[prevBale] |
838 | if joint ~= nil then |
839 | removeJoint(joint.jointIndex) |
840 | end |
841 | end |
842 | end |
843 | |
844 | table.remove(self.bales, #self.bales) |
845 | |
846 | bale:setConnectedInlineBale(nil) |
847 | |
848 | -- replace InlineBaleSingle with a normal Bale again |
849 | -- attributes stay the same |
850 | if replaceBale == nil or replaceBale then |
851 | local attributes = bale:getBaleAttributes() |
852 | |
853 | local newBale = Bale.new(self.isServer, self.isClient) |
854 | local x, y, z = getWorldTranslation(bale.nodeId) |
855 | local rx, ry, rz = getWorldRotation(bale.nodeId) |
856 | |
857 | if newBale:loadFromConfigXML(attributes.xmlFilename, x, y, z, rx, ry, rz) then |
858 | attributes.wrapDiffuse = self.wrapDiffuse |
859 | attributes.wrapNormal = self.wrapNormal |
860 | |
861 | newBale:applyBaleAttributes(attributes) |
862 | newBale:register() |
863 | newBale:open() |
864 | |
865 | bale:delete() |
866 | end |
867 | end |
868 | |
869 | if #self.bales == 0 then |
870 | self:delete() |
871 | end |
872 | |
873 | self:raiseActive() |
874 | end |
791 | function InlineBale:openBaleAtPosition(x, y, z) |
792 | local distance1 = 0 |
793 | local distance2 = 1 |
794 | local fristBale = self.bales[1] |
795 | local lastBale = self.bales[#self.bales] |
796 | |
797 | if #self.bales > 1 then |
798 | local bx, by, bz = getWorldTranslation(fristBale.nodeId) |
799 | distance1 = MathUtil.vector3Length(x-bx, y-by, z-bz) |
800 | |
801 | bx, by, bz = getWorldTranslation(lastBale.nodeId) |
802 | distance2 = MathUtil.vector3Length(x-bx, y-by, z-bz) |
803 | end |
804 | |
805 | if distance1 < distance2 then |
806 | self:openBale(fristBale, true) |
807 | else |
808 | self:openBale(lastBale, false) |
809 | end |
810 | end |
536 | function InlineBale:replacePendingBale(spawnNode, color) |
537 | local replaced, baleId = false, nil |
538 | if self.pendingBale ~= nil then |
539 | local attributes = self.pendingBale:getBaleAttributes() |
540 | |
541 | local bale = InlineBaleSingle.new(self.isServer, self.isClient) |
542 | local x, y, z = getWorldTranslation(spawnNode) |
543 | local rx, ry, rz = getWorldRotation(spawnNode) |
544 | |
545 | if bale:loadFromConfigXML(self.replacementBaleFilename or attributes.xmlFilename, x, y, z, rx, ry, rz) then |
546 | attributes.wrapDiffuse = self.wrapDiffuse |
547 | attributes.wrapNormal = self.wrapNormal |
548 | |
549 | bale:applyBaleAttributes(attributes) |
550 | bale:register() |
551 | |
552 | self.pendingBale:delete() |
553 | |
554 | if color ~= nil then |
555 | local r, g, b, a = unpack(color) |
556 | bale:setColor(r, g, b, a) |
557 | end |
558 | |
559 | baleId = NetworkUtil.getObjectId(bale) |
560 | |
561 | self.bales[#self.bales] = bale |
562 | self.pendingBale = bale |
563 | bale:setConnectedInlineBale(self) |
564 | |
565 | bale:addDeleteListener(self, "onBaleDeleted") |
566 | |
567 | replaced = true |
568 | end |
569 | end |
570 | |
571 | return replaced, baleId |
572 | end |
647 | function InlineBale:setBaleJointLimits(jointIndex, alpha) |
648 | local x, y, z = MathUtil.vector3ArrayLerp(self.startRotLimit, self.endRotLimit, alpha) |
649 | setJointRotationLimit(jointIndex, 0, true, -x, x) |
650 | setJointRotationLimit(jointIndex, 1, true, -y, y) |
651 | setJointRotationLimit(jointIndex, 2, true, -z, z) |
652 | |
653 | x, y, z = MathUtil.vector3ArrayLerp(self.startTransLimit, self.endTransLimit, alpha) |
654 | setJointTranslationLimit(jointIndex, 0, true, -x, x) |
655 | setJointTranslationLimit(jointIndex, 1, true, -y, y) |
656 | setJointTranslationLimit(jointIndex, 2, true, -z, z) |
657 | end |
359 | function InlineBale:updateTick(dt) |
360 | if self.isServer then |
361 | if #self.balesToLoad > 0 then |
362 | local allBalesAvailable = true |
363 | for _, bale in ipairs(self.balesToLoad) do |
364 | if g_currentMission.itemSystem:getItemBySaveId(bale.saveId) == nil then |
365 | allBalesAvailable = false |
366 | end |
367 | end |
368 | |
369 | if allBalesAvailable then |
370 | for _, bale in ipairs(self.balesToLoad) do |
371 | local baleObject = g_currentMission.itemSystem:getItemBySaveId(bale.saveId) |
372 | if baleObject:isa(InlineBaleSingle) then |
373 | self:addBale(baleObject) |
374 | self:connectPendingBale(self.connectorFilename) |
375 | self:updateBaleJoints(9999) |
376 | else |
377 | Logging.error("Invalid inline bale found") |
378 | end |
379 | end |
380 | |
381 | self.balesToLoad = {} |
382 | end |
383 | |
384 | self:raiseActive() |
385 | end |
386 | |
387 | self:updateBaleJoints(dt) |
388 | |
389 | if self.wrappingNode ~= nil and self.wrappingState < 1 then |
390 | local wx, _, wz = getWorldTranslation(self.wrappingNode) |
391 | local globalWrappingState = 0 |
392 | for i, bale in ipairs(self.bales) do |
393 | if bale ~= self.pendingBale then |
394 | local halfWidth = bale.width / 2 |
395 | local sx, sy, sz = localToWorld(bale.nodeId, self.wrappingAxisScale[1]*halfWidth, self.wrappingAxisScale[2]*halfWidth, self.wrappingAxisScale[3]*halfWidth) |
396 | local ex, ey, ez = localToWorld(bale.nodeId, self.wrappingAxisScale[1]*-halfWidth, self.wrappingAxisScale[2]*-halfWidth, self.wrappingAxisScale[3]*-halfWidth) |
397 | |
398 | local dirX, dirZ = MathUtil.vector2Normalize(sx-ex, sz-ez) |
399 | local x, z = MathUtil.projectOnLine(wx, wz, sx, sz, dirX, dirZ) |
400 | local dot = MathUtil.clamp(MathUtil.getProjectOnLineParameter(wx, wz, sx, sz, dirX, dirZ), 0, 1) |
401 | local y = sy * dot + ey * (1-dot) |
402 | local length1 = MathUtil.vector3Length(sx-x, sy-y, sz-z) |
403 | |
404 | local pos = MathUtil.clamp(length1 / bale.width, 0, 1) |
405 | |
406 | local s2x, s2y, s2z = localToWorld(bale.nodeId, self.wrappingAxisScale[1]*(halfWidth+0.1), self.wrappingAxisScale[2]*(halfWidth+0.1), self.wrappingAxisScale[3]*(halfWidth+0.1)) |
407 | local length2 = MathUtil.vector3Length(s2x-x, s2y-y, s2z-z) |
408 | if length2 < length1 then |
409 | pos = 0 |
410 | end |
411 | |
412 | if self.wrappingStateCurve ~= nil then |
413 | local wrappingState = math.max(self.wrappingStateCurve:get(pos), bale.wrappingState) |
414 | bale:setWrappingState(wrappingState) |
415 | |
416 | globalWrappingState = globalWrappingState + wrappingState |
417 | end |
418 | end |
419 | end |
420 | |
421 | self.wrappingState = globalWrappingState / #self.bales |
422 | |
423 | self:raiseActive() |
424 | end |
425 | |
426 | if self.pendingBale == nil then |
427 | if #self.bales ~= self.numBalesSent then |
428 | self:raiseDirtyFlags(self.balesDirtyFlag) |
429 | end |
430 | end |
431 | |
432 | if self.removeEmptyInlineBale then |
433 | self:delete() |
434 | end |
435 | |
436 | if self.wakeUpDelay > 0 then |
437 | self.wakeUpDelay = self.wakeUpDelay - dt |
438 | if self.wakeUpDelay <= 0 then |
439 | self:wakeUp() |
440 | end |
441 | self:raiseActive() |
442 | end |
443 | else |
444 | if #self.balesToLoad > 0 then |
445 | local readyToAdd = true |
446 | for i, baleObjectId in ipairs(self.balesToLoad) do |
447 | if NetworkUtil.getObject(baleObjectId) == nil then |
448 | readyToAdd = false |
449 | end |
450 | end |
451 | |
452 | if readyToAdd then |
453 | for i, baleObjectId in ipairs(self.balesToLoad) do |
454 | local baleObject = NetworkUtil.getObject(baleObjectId) |
455 | if baleObject ~= nil then |
456 | self:addBale(baleObject) |
457 | end |
458 | end |
459 | |
460 | self.balesToLoad = {} |
461 | |
462 | -- recreate connectors |
463 | for i=1, #self.bales-1 do |
464 | if self.bales[i] ~= nil and self.bales[i+1] ~= nil then |
465 | self:loadBaleConnector(self.bales[i], self.bales[i+1], self.connectorFilename) |
466 | end |
467 | end |
468 | |
469 | end |
470 | |
471 | self:raiseActive() |
472 | end |
473 | end |
474 | end |