27 | function InlineWrapper.initSpecialization() |
28 | g_storeManager:addSpecType("inlineWrapperBaleSizeRound", "shopListAttributeIconBaleWrapperBaleSizeRound", InlineWrapper.loadSpecValueBaleSizeRound, InlineWrapper.getSpecValueBaleSizeRound, "vehicle") |
29 | g_storeManager:addSpecType("inlineWrapperBaleSizeSquare", "shopListAttributeIconBaleWrapperBaleSizeSquare", InlineWrapper.loadSpecValueBaleSizeSquare, InlineWrapper.getSpecValueBaleSizeSquare, "vehicle") |
30 | |
31 | local schema = Vehicle.xmlSchema |
32 | schema:setXMLSpecializationType("InlineWrapper") |
33 | |
34 | schema:register(XMLValueType.NODE_INDEX, "vehicle.inlineWrapper.baleTrigger#node", "Bale pickup trigger") |
35 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.baleTrigger#minFoldTime", "Min. folding time for bale pickup", 0) |
36 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.baleTrigger#maxFoldTime", "Max. folding time for bale pickup", 1) |
37 | schema:register(XMLValueType.NODE_INDEX, "vehicle.inlineWrapper.wrapTrigger#node", "Wrap trigger") |
38 | |
39 | schema:register(XMLValueType.NODE_INDEX, "vehicle.inlineWrapper.baleTypes.baleType(?)#startNode", "Start placement node for bale") |
40 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.baleTypes.baleType(?).railing#width", "Railing width to set") |
41 | schema:register(XMLValueType.STRING, "vehicle.inlineWrapper.baleTypes.baleType(?).inlineBale#filename", "Path to inline bale xml file") |
42 | |
43 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.baleTypes.baleType(?).size#diameter", "Bale diameter") |
44 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.baleTypes.baleType(?).size#width", "Bale width") |
45 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.baleTypes.baleType(?).size#height", "Bale height") |
46 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.baleTypes.baleType(?).size#length", "Bale length") |
47 | |
48 | schema:register(XMLValueType.STRING, "vehicle.inlineWrapper.railings#animation", "Railing animation") |
49 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.railings#animStartX", "Railing width at start of animation") |
50 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.railings#animEndX", "Railing width at end of animation") |
51 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.railings#defaultX", "Default railing width", 1) |
52 | |
53 | schema:register(XMLValueType.NODE_INDEX, "vehicle.inlineWrapper.wrapping#startNode", "Reference node for warpping state of bale") |
54 | |
55 | schema:register(XMLValueType.NODE_INDEX, "vehicle.inlineWrapper.steeringNodes.steeringNode(?)#node", "Steering node that is aligned to the start wrapping direction") |
56 | |
57 | schema:register(XMLValueType.NODE_INDEX, "vehicle.inlineWrapper.wrappingNodes.wrappingNode(?)#node", "Wrapping node") |
58 | schema:register(XMLValueType.NODE_INDEX, "vehicle.inlineWrapper.wrappingNodes.wrappingNode(?)#target", "Target node that is aliged to the bale") |
59 | schema:register(XMLValueType.VECTOR_TRANS, "vehicle.inlineWrapper.wrappingNodes.wrappingNode(?)#startTrans", "Start translation") |
60 | |
61 | schema:register(XMLValueType.STRING, "vehicle.inlineWrapper.animations#pusher", "Pusher animation", "pusherAnimation") |
62 | schema:register(XMLValueType.STRING, "vehicle.inlineWrapper.animations#wrapping", "Wrapping animation", "wrappingAnimation") |
63 | schema:register(XMLValueType.STRING, "vehicle.inlineWrapper.animations#pushOff", "Push bale off animation", "pushOffAnimation") |
64 | |
65 | schema:register(XMLValueType.STRING, "vehicle.inlineWrapper.pushing#brakeForce", "Brake force while pushing", 0) |
66 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.pushing#openBrakeTime", "Pusher animation time to open brake", 0.1) |
67 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper.pushing#closeBrakeTime", "Pusher animation time to close brake", 0.5) |
68 | schema:register(XMLValueType.INT, "vehicle.inlineWrapper.pushing#minBaleAmount", "Min. bales wrapped to open brake", 4) |
69 | |
70 | schema:register(XMLValueType.FLOAT, "vehicle.inlineWrapper#baleMovedThreshold", "Bale moved threshold for starting wrappign animation", 0.05) |
71 | schema:register(XMLValueType.INT, "vehicle.inlineWrapper#numObjectBits", "Num bits for sending bales", 4) |
72 | |
73 | SoundManager.registerSampleXMLPaths(schema, "vehicle.inlineWrapper.sounds", "wrap") |
74 | SoundManager.registerSampleXMLPaths(schema, "vehicle.inlineWrapper.sounds", "start") |
75 | SoundManager.registerSampleXMLPaths(schema, "vehicle.inlineWrapper.sounds", "stop") |
76 | |
77 | schema:setXMLSpecializationType() |
78 | end |
901 | function InlineWrapper:inlineBaleTriggerCallback(triggerId, otherActorId, onEnter, onLeave, onStay, otherShapeId) |
902 | if self.isServer then |
903 | local object = g_currentMission:getNodeObject(otherActorId) |
904 | if object ~= nil and object:isa(Bale) then |
905 | local objectId = NetworkUtil.getObjectId(object) |
906 | local spec = self.spec_inlineWrapper |
907 | if onEnter then |
908 | if not object:isa(InlineBaleSingle) then |
909 | if self:getWrapperBaleType(object) ~= nil then |
910 | spec.pendingSingleBales[objectId] = objectId |
911 | end |
912 | else |
913 | spec.enteredInlineBales[objectId] = objectId |
914 | |
915 | -- set wrapper and wrapping node again if the bale reenteres |
916 | local connectedInlineBale = object:getConnectedInlineBale() |
917 | if connectedInlineBale ~= nil then |
918 | connectedInlineBale:setCurrentWrapperInfo(self, spec.wrappingStartNode) |
919 | else |
920 | -- add information to inline bale if the bale was added to the inline bale (while loading) |
921 | object.inlineWrapperToAdd = {wrapper=self, wrappingNode=spec.wrappingStartNode} |
922 | end |
923 | end |
924 | elseif onLeave then |
925 | spec.pendingSingleBales[objectId] = nil |
926 | spec.enteredInlineBales[objectId] = nil |
927 | |
928 | if object:isa(InlineBaleSingle) then |
929 | local connectedInlineBale = object:getConnectedInlineBale() |
930 | if connectedInlineBale ~= nil then |
931 | local bales = connectedInlineBale:getBales() |
932 | local removeFromWrapper = true |
933 | for _, bale in ipairs(bales) do |
934 | local baleId = NetworkUtil.getObjectId(bale) |
935 | if spec.pendingSingleBales[baleId] ~= nil or |
936 | spec.enteredInlineBales[baleId] ~= nil then |
937 | removeFromWrapper = false |
938 | break |
939 | end |
940 | end |
941 | |
942 | if removeFromWrapper then |
943 | connectedInlineBale:setCurrentWrapperInfo(nil, nil) |
944 | self:setCurrentInlineBale(nil) |
945 | end |
946 | end |
947 | end |
948 | end |
949 | |
950 | self:raiseDirtyFlags(spec.inlineBalesDirtyFlag) |
951 | end |
952 | end |
953 | end |
130 | function InlineWrapper:onLoad(savegame) |
131 | local spec = self.spec_inlineWrapper |
132 | |
133 | local baseKey = "vehicle.inlineWrapper" |
134 | |
135 | spec.triggerNode = self.xmlFile:getValue(baseKey..".baleTrigger#node", nil, self.components, self.i3dMappings) |
136 | if spec.triggerNode ~= nil then |
137 | addTrigger(spec.triggerNode, "inlineBaleTriggerCallback", self) |
138 | end |
139 | |
140 | spec.wrapTriggerNode = self.xmlFile:getValue(baseKey..".wrapTrigger#node", nil, self.components, self.i3dMappings) |
141 | if spec.wrapTriggerNode ~= nil then |
142 | addTrigger(spec.wrapTriggerNode, "inlineWrapTriggerCallback", self) |
143 | end |
144 | |
145 | spec.minFoldTime = self.xmlFile:getValue(baseKey..".baleTrigger#minFoldTime", 0) |
146 | spec.maxFoldTime = self.xmlFile:getValue(baseKey..".baleTrigger#maxFoldTime", 1) |
147 | |
148 | spec.baleTypes = {} |
149 | self.xmlFile:iterate(baseKey .. ".baleTypes.baleType", function(index, key) |
150 | local entry = {} |
151 | entry.startNode = self.xmlFile:getValue(key.."#startNode", nil, self.components, self.i3dMappings) |
152 | if entry.startNode ~= nil then |
153 | entry.railingWidth = self.xmlFile:getValue(key..".railing#width") |
154 | |
155 | entry.inlineBaleFilename = Utils.getFilename(self.xmlFile:getValue(key..".inlineBale#filename"), self.baseDirectory) |
156 | if entry.inlineBaleFilename ~= nil then |
157 | entry.diameter = MathUtil.round(self.xmlFile:getValue(key..".size#diameter", 0), 2) |
158 | entry.width = MathUtil.round(self.xmlFile:getValue(key..".size#width", 0), 2) |
159 | entry.isRoundBale = entry.diameter ~= 0 |
160 | if not entry.isRoundBale then |
161 | entry.height = MathUtil.round(self.xmlFile:getValue(key..".size#height", 0), 2) |
162 | entry.length = MathUtil.round(self.xmlFile:getValue(key..".size#length", 0), 2) |
163 | end |
164 | |
165 | entry.index = #spec.baleTypes + 1 |
166 | |
167 | table.insert(spec.baleTypes, entry) |
168 | else |
169 | Logging.xmlError(self.xmlFile, "Failed to load bale type. Missing inline bale filename! '%s'", key) |
170 | end |
171 | else |
172 | Logging.xmlError(self.xmlFile, "Failed to load bale type. Missing start node! '%s'", key) |
173 | end |
174 | end) |
175 | |
176 | spec.railingsAnimation = self.xmlFile:getValue(baseKey..".railings#animation") |
177 | spec.railingsAnimationStartX = self.xmlFile:getValue(baseKey..".railings#animStartX") |
178 | spec.railingsAnimationEndX = self.xmlFile:getValue(baseKey..".railings#animEndX") |
179 | spec.railingStartX = self.xmlFile:getValue(baseKey..".railings#defaultX", 1) |
180 | spec.currentPosition = spec.railingStartX + 0.01 |
181 | spec.targetPosition = spec.railingStartX + 0.01 |
182 | |
183 | spec.wrappingStartNode = self.xmlFile:getValue(baseKey..".wrapping#startNode", nil, self.components, self.i3dMappings) |
184 | |
185 | spec.steeringNodes = {} |
186 | self.xmlFile:iterate(baseKey .. ".steeringNodes.steeringNode", function(_, key) |
187 | local entry = {} |
188 | entry.node = self.xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
189 | |
190 | if entry.node ~= nil then |
191 | entry.startRot = {getRotation(entry.node)} |
192 | table.insert(spec.steeringNodes, entry) |
193 | end |
194 | end) |
195 | |
196 | spec.wrappingNodes = {} |
197 | self.xmlFile:iterate(baseKey .. ".wrappingNodes.wrappingNode", function(_, key) |
198 | local entry = {} |
199 | entry.node = self.xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
200 | entry.target = self.xmlFile:getValue(key.."#target", nil, self.components, self.i3dMappings) |
201 | |
202 | if entry.node ~= nil and entry.target ~= nil then |
203 | entry.startTrans = self.xmlFile:getValue(key.."#startTrans", {getTranslation(entry.target)}, true) |
204 | setTranslation(entry.target, entry.startTrans[1], entry.startTrans[2], entry.startTrans[3]) |
205 | |
206 | table.insert(spec.wrappingNodes, entry) |
207 | end |
208 | end) |
209 | |
210 | spec.animations = {} |
211 | spec.animations.pusher = self.xmlFile:getValue(baseKey..".animations#pusher", "pusherAnimation") |
212 | spec.animations.wrapping = self.xmlFile:getValue(baseKey..".animations#wrapping", "wrappingAnimation") |
213 | spec.animations.pushOff = self.xmlFile:getValue(baseKey..".animations#pushOff", "pushOffAnimation") |
214 | |
215 | spec.pushingBrakeForce = self.xmlFile:getValue(baseKey..".pushing#brakeForce", 0) |
216 | spec.pushingOpenBrakeTime = self.xmlFile:getValue(baseKey..".pushing#openBrakeTime", 0.1) |
217 | spec.pushingCloseBrakeTime = self.xmlFile:getValue(baseKey..".pushing#closeBrakeTime", 0.5) |
218 | spec.pushingMinBaleAmount = self.xmlFile:getValue(baseKey..".pushing#minBaleAmount", 4) |
219 | |
220 | spec.baleMovedThreshold = self.xmlFile:getValue(baseKey.."#baleMovedThreshold", 0.05) |
221 | |
222 | spec.pusherAnimationDirty = false |
223 | |
224 | spec.pendingSingleBales = {} |
225 | spec.enteredInlineBales = {} |
226 | spec.enteredBalesToWrap = {} |
227 | |
228 | spec.numObjectBits = self.xmlFile:getValue("vehicle.inlineWrapper#numObjectBits", 4) |
229 | spec.inlineBalesDirtyFlag = self:getNextDirtyFlag() |
230 | |
231 | spec.currentLineDirection = nil |
232 | spec.lineDirection = nil |
233 | spec.activatable = InlineWrapperActivatable.new(self) |
234 | |
235 | if self.isClient then |
236 | spec.samples = {} |
237 | spec.samples.wrap = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey..".sounds", "wrap", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
238 | spec.samples.start = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey..".sounds", "start", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
239 | spec.samples.stop = g_soundManager:loadSampleFromXML(self.xmlFile, baseKey..".sounds", "stop", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self) |
240 | end |
241 | end |
401 | function InlineWrapper:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
402 | local spec = self.spec_inlineWrapper |
403 | if self.isServer then |
404 | local pendingBaleId = next(spec.pendingSingleBales) |
405 | local pendingBale = NetworkUtil.getObject(pendingBaleId) |
406 | if pendingBale ~= nil and self:getIsInlineBalingAllowed() then |
407 | local baleType = self:getWrapperBaleType(pendingBale) |
408 | local lastBaleId = next(spec.enteredInlineBales) |
409 | local lastBale = NetworkUtil.getObject(lastBaleId) |
410 | local inlineBale |
411 | local success = false |
412 | if lastBale == nil then |
413 | -- first bale |
414 | inlineBale = InlineBale.new(self.isServer, self.isClient) |
415 | |
416 | if inlineBale:loadFromConfigXML(baleType.inlineBaleFilename) then |
417 | inlineBale:setOwnerFarmId(self:getActiveFarm(), true) |
418 | |
419 | inlineBale:setCurrentWrapperInfo(self, spec.wrappingStartNode) |
420 | |
421 | inlineBale:register() |
422 | |
423 | success = inlineBale:addBale(pendingBale, baleType) |
424 | else |
425 | inlineBale:delete() |
426 | end |
427 | else |
428 | -- add another bale |
429 | if lastBale:isa(InlineBaleSingle) then |
430 | inlineBale = lastBale:getConnectedInlineBale() |
431 | if inlineBale ~= nil then |
432 | |
433 | success = inlineBale:addBale(pendingBale, baleType) |
434 | |
435 | if success then |
436 | local currentInlineBale = self:getCurrentInlineBale() |
437 | currentInlineBale:setCurrentWrapperInfo(self, spec.wrappingStartNode) |
438 | end |
439 | end |
440 | end |
441 | end |
442 | |
443 | if success then |
444 | spec.pendingSingleBales[pendingBaleId] = nil |
445 | spec.enteredInlineBales[pendingBaleId] = pendingBaleId |
446 | |
447 | spec.pusherAnimationDirty = true |
448 | self:setCurrentInlineBale(inlineBale) |
449 | |
450 | g_currentMission.activatableObjectsSystem:addActivatable(spec.activatable) |
451 | |
452 | local stats = g_currentMission:farmStats(self:getOwnerFarmId()) |
453 | local total = stats:updateStats("wrappedBales", 1) |
454 | g_achievementManager:tryUnlock("WrappedBales", total) |
455 | |
456 | self:raiseDirtyFlags(spec.inlineBalesDirtyFlag) |
457 | end |
458 | end |
459 | end |
460 | |
461 | -- set currentInlineBale not matter if a new bale ist getting mounted (necessary for clients and singleplayer if the savegame if reloaded) |
462 | local inlineBaleId = next(spec.enteredInlineBales) |
463 | local bale = NetworkUtil.getObject(inlineBaleId) |
464 | if bale ~= nil then |
465 | if self:getCurrentInlineBale() == nil then |
466 | if bale:isa(InlineBaleSingle) then |
467 | local inlineBale = bale:getConnectedInlineBale() |
468 | if inlineBale ~= nil then |
469 | self:setCurrentInlineBale(inlineBale) |
470 | |
471 | g_currentMission.activatableObjectsSystem:addActivatable(spec.activatable) |
472 | |
473 | self:updateWrappingNodes() |
474 | |
475 | local currentInlineBale = self:getCurrentInlineBale() |
476 | currentInlineBale:setCurrentWrapperInfo(self, spec.wrappingStartNode) |
477 | end |
478 | end |
479 | end |
480 | else |
481 | self:setCurrentInlineBale(nil) |
482 | end |
483 | |
484 | local needsSteering = (next(spec.enteredInlineBales) ~= nil or spec.pushOffStarted) and self:getAttacherVehicle() == nil |
485 | local steeringActive = needsSteering and not self:getIsControlled() |
486 | |
487 | if spec.lineDirection == nil and needsSteering then |
488 | local x, _, z = localDirectionToWorld(self.components[1].node, 0, 0, -1) |
489 | spec.lineDirection = {x, z} |
490 | elseif spec.lineDirection ~= nil and not needsSteering then |
491 | spec.lineDirection = nil |
492 | end |
493 | |
494 | if not steeringActive then |
495 | if spec.currentLineDirection ~= nil then |
496 | spec.currentLineDirection = nil |
497 | self:updateInlineSteeringWheels() |
498 | end |
499 | else |
500 | spec.currentLineDirection = spec.lineDirection |
501 | end |
502 | |
503 | if spec.currentLineDirection ~= nil then |
504 | self:updateInlineSteeringWheels(spec.currentLineDirection[1], spec.currentLineDirection[2]) |
505 | end |
506 | |
507 | if self.isServer then |
508 | spec.releaseBrake = false |
509 | local currentInlineBale = self:getCurrentInlineBale() |
510 | |
511 | if spec.pusherAnimationDirty then |
512 | local allowedToPush = true |
513 | |
514 | for _, baleId in pairs(spec.pendingSingleBales) do |
515 | if not self:getAllowBalePushing(NetworkUtil.getObject(baleId)) then |
516 | allowedToPush = false |
517 | break |
518 | end |
519 | end |
520 | |
521 | if allowedToPush then |
522 | for _, baleId in pairs(spec.enteredInlineBales) do |
523 | if not self:getAllowBalePushing(NetworkUtil.getObject(baleId)) then |
524 | allowedToPush = false |
525 | break |
526 | end |
527 | end |
528 | end |
529 | |
530 | if allowedToPush then |
531 | if currentInlineBale ~= nil then |
532 | local pendingBale = currentInlineBale:getPendingBale() |
533 | local pendingBaleId = NetworkUtil.getObjectId(pendingBale) |
534 | local baleType = self:getWrapperBaleType(pendingBale) |
535 | |
536 | local replaced, newBaleId = currentInlineBale:replacePendingBale(baleType.startNode, ConfigurationUtil.getColorByConfigId(self, "wrappingColor", self.configurations["wrappingColor"])) |
537 | if replaced then |
538 | spec.enteredInlineBales[pendingBaleId] = nil |
539 | spec.enteredInlineBales[newBaleId] = newBaleId |
540 | end |
541 | |
542 | self:playAnimation(spec.animations.pusher, 1, 0) |
543 | spec.pusherAnimationDirty = false |
544 | currentInlineBale:connectPendingBale() |
545 | self:raiseDirtyFlags(spec.inlineBalesDirtyFlag) |
546 | end |
547 | end |
548 | |
549 | self:raiseActive() |
550 | end |
551 | |
552 | if self:getAttacherVehicle() == nil then |
553 | local allowBrakeOpening = true |
554 | if currentInlineBale ~= nil then |
555 | if currentInlineBale:getNumberOfBales() < spec.pushingMinBaleAmount then |
556 | allowBrakeOpening = false |
557 | end |
558 | end |
559 | |
560 | local animTime = self:getAnimationTime(spec.animations.pusher) |
561 | local isPushing = self:getIsAnimationPlaying(spec.animations.pusher) and animTime > spec.pushingOpenBrakeTime and animTime < spec.pushingCloseBrakeTime |
562 | local currentSpeed = self:getAnimationSpeed(spec.animations.pushOff) |
563 | local isPushingOff = self:getIsAnimationPlaying(spec.animations.pushOff) and currentSpeed > 0 |
564 | |
565 | local releaseBrake = isPushing or isPushingOff |
566 | |
567 | if allowBrakeOpening then |
568 | spec.releaseBrake = releaseBrake |
569 | end |
570 | end |
571 | end |
572 | |
573 | local playWrapAnimation = false |
574 | for _, wrapBaleId in pairs(spec.enteredBalesToWrap) do |
575 | local wrapBale = NetworkUtil.getObject(wrapBaleId) |
576 | if wrapBale ~= nil then |
577 | if entityExists(wrapBale.nodeId) then |
578 | local x, y, z = localToLocal(wrapBale.nodeId, self.components[1].node, 0, 0, 0) |
579 | if wrapBale.lastWrapTranslation ~= nil and wrapBale.lastWrapMoveTime ~= nil then |
580 | if math.abs(wrapBale.lastWrapTranslation[1]-x) + math.abs(wrapBale.lastWrapTranslation[2]-y) + math.abs(wrapBale.lastWrapTranslation[3]-z) > spec.baleMovedThreshold then |
581 | wrapBale.lastWrapMoveTime = g_currentMission.time |
582 | wrapBale.lastWrapTranslation = {x, y, z} |
583 | end |
584 | else |
585 | wrapBale.lastWrapMoveTime = -math.huge |
586 | wrapBale.lastWrapTranslation = {x, y, z} |
587 | end |
588 | |
589 | if wrapBale.lastWrapMoveTime + 1500 > g_currentMission.time then |
590 | playWrapAnimation = true |
591 | break |
592 | end |
593 | |
594 | self:raiseActive() |
595 | end |
596 | end |
597 | end |
598 | |
599 | if playWrapAnimation then |
600 | if not self:getIsAnimationPlaying(spec.animations.wrapping) then |
601 | self:playAnimation(spec.animations.wrapping, 1, self:getAnimationTime(spec.animations.wrapping), true) |
602 | end |
603 | |
604 | if self.isClient then |
605 | if not g_soundManager:getIsSamplePlaying(spec.samples.start) and not g_soundManager:getIsSamplePlaying(spec.samples.wrap) then |
606 | g_soundManager:playSample(spec.samples.start) |
607 | g_soundManager:playSample(spec.samples.wrap, 0, spec.samples.start) |
608 | end |
609 | end |
610 | else |
611 | self:stopAnimation(spec.animations.wrapping, true) |
612 | |
613 | if self.isClient then |
614 | if g_soundManager:getIsSamplePlaying(spec.samples.start) or g_soundManager:getIsSamplePlaying(spec.samples.wrap) then |
615 | g_soundManager:stopSample(spec.samples.start) |
616 | g_soundManager:stopSample(spec.samples.wrap) |
617 | g_soundManager:playSample(spec.samples.stop) |
618 | end |
619 | end |
620 | end |
621 | |
622 | local baleId = next(spec.pendingSingleBales) or next(spec.enteredInlineBales) |
623 | bale = NetworkUtil.getObject(baleId) |
624 | if bale ~= nil then |
625 | local baleType = self:getWrapperBaleType(bale) |
626 | |
627 | local currentInlineBale = self:getCurrentInlineBale() |
628 | if currentInlineBale ~= nil then |
629 | if not currentInlineBale:getIsBaleAllowed(bale, baleType) then |
630 | baleType = nil |
631 | end |
632 | end |
633 | |
634 | if baleType ~= nil then |
635 | spec.targetPosition = baleType.railingWidth |
636 | |
637 | self:updateWrapperRailings(spec.targetPosition, dt) |
638 | end |
639 | else |
640 | self:updateWrapperRailings(spec.railingStartX, dt) |
641 | end |
642 | |
643 | -- reset push off arm |
644 | if self.isServer then |
645 | if spec.pushOffStarted ~= nil and spec.pushOffStarted then |
646 | if not self:getIsAnimationPlaying(spec.animations.pushOff) then |
647 | self:playAnimation(spec.animations.pushOff, -1, 1) |
648 | spec.pushOffStarted = nil |
649 | end |
650 | end |
651 | end |
652 | |
653 | if self.isClient then |
654 | local actionEvent = spec.actionEvents[InputAction.ACTIVATE_OBJECT] |
655 | if actionEvent ~= nil then |
656 | g_inputBinding:setActionEventActive(actionEvent.actionEventId, self:getCanPushOff()) |
657 | end |
658 | end |
659 | end |
737 | function InlineWrapper:updateRoundBaleWrappingNode(bale, wrappingNode, x, y, z) |
738 | local baleNode = bale.nodeId |
739 | local baleRadius = bale.diameter / 2 |
740 | local steps = 32 |
741 | local intersectOffset = 0.01 |
742 | local foilOffset = -0.03 |
743 | |
744 | local w1x, w1y, w1z = worldToLocal(baleNode, x, y, z) |
745 | |
746 | local distanceToCenter = MathUtil.vector3Length(w1x, w1y, 0) |
747 | local maxDirY = -math.huge |
748 | local targetX, targetY, targetZ |
749 | for i=1, steps do |
750 | local a = (i/steps)*2*math.pi |
751 | |
752 | local c = math.cos(a) * (baleRadius+intersectOffset) |
753 | local s = math.sin(a) * (baleRadius+intersectOffset) |
754 | |
755 | local distance = MathUtil.vector2Length(c-w1x, s-w1y) |
756 | if distance < distanceToCenter then |
757 | local intersect, _, _, _, _ = MathUtil.getCircleLineIntersection(0, 0, baleRadius, w1x, w1y, c, s) |
758 | |
759 | if not intersect then |
760 | local px, py, pz = localToWorld(baleNode, c, s, 0) |
761 | local _, wrapDirY, _ = worldToLocal(wrappingNode, px, py, pz) |
762 | if wrapDirY > maxDirY then |
763 | maxDirY = wrapDirY |
764 | |
765 | targetX, targetY, targetZ = localToWorld(baleNode, math.cos(a) * (baleRadius+foilOffset), math.sin(a) * (baleRadius+foilOffset), w1z) |
766 | end |
767 | end |
768 | end |
769 | end |
770 | |
771 | return targetX, targetY, targetZ |
772 | end |
776 | function InlineWrapper:updateSquareBaleWrappingNode(bale, wrappingNode, x, y, z) |
777 | local baleNode = bale.nodeId |
778 | |
779 | local minAngle = math.huge |
780 | local targetX, targetY, targetZ |
781 | local height = bale.height / 2 |
782 | local length = bale.length / 2 |
783 | local intersectOffset = 0.01 |
784 | local foilOffset = -0.05 |
785 | |
786 | local w1x, w1y, w1z = worldToLocal(baleNode, x, y, z) |
787 | |
788 | if bale.wrappingEdges == nil then |
789 | bale.wrappingEdges = {} |
790 | bale.wrappingEdges[1] = {0, height, -length} |
791 | bale.wrappingEdges[2] = {0, -height, -length} |
792 | bale.wrappingEdges[3] = {0, -height, length} |
793 | bale.wrappingEdges[4] = {0, height, length} |
794 | end |
795 | |
796 | for _, edge in ipairs(bale.wrappingEdges) do |
797 | local edgeY = edge[2] + MathUtil.sign(edge[2]) * intersectOffset |
798 | local edgeZ = edge[3] + MathUtil.sign(edge[3]) * intersectOffset |
799 | |
800 | local intersect = false |
801 | for i=1, 4 do |
802 | local i2 = i <= 3 and i + 1 or 1 |
803 | intersect = intersect or MathUtil.getLineBoundingVolumeIntersect(edgeY, edgeZ, w1y, w1z, bale.wrappingEdges[i][2], bale.wrappingEdges[i][3], bale.wrappingEdges[i2][2], bale.wrappingEdges[i2][3]) |
804 | end |
805 | |
806 | if not intersect then |
807 | local px, py, pz = localToWorld(baleNode, w1x, edgeY, edgeZ) |
808 | local _, wrapDirY, wrapDirZ = worldToLocal(wrappingNode, px, py, pz) |
809 | local angle = MathUtil.getYRotationFromDirection(wrapDirY, wrapDirZ) |
810 | |
811 | if angle < 0 then |
812 | angle = math.pi + (math.pi+angle) |
813 | end |
814 | |
815 | if angle < minAngle then |
816 | minAngle = angle |
817 | |
818 | targetX, targetY, targetZ = localToWorld(baleNode, w1x, edge[2] + MathUtil.sign(edge[2]) * foilOffset, edge[3] + MathUtil.sign(edge[3]) * foilOffset) |
819 | end |
820 | end |
821 | end |
822 | |
823 | return targetX, targetY, targetZ |
824 | end |
663 | function InlineWrapper:updateWrappingNodes() |
664 | local spec = self.spec_inlineWrapper |
665 | |
666 | local inlineBale = self:getCurrentInlineBale() |
667 | if inlineBale ~= nil then |
668 | local bales = spec.enteredBalesToWrap |
669 | |
670 | for _, wrappingNode in ipairs(spec.wrappingNodes) do |
671 | local x, y, z = getWorldTranslation(wrappingNode.node) |
672 | local minDistance = math.huge |
673 | local minBale |
674 | for _, baleId in pairs(bales) do |
675 | local bale = NetworkUtil.getObject(baleId) |
676 | if bale ~= nil then |
677 | if bale ~= inlineBale:getPendingBale() then |
678 | local bx, _, bz = worldToLocal(bale.nodeId, x, y, z) |
679 | local x1, y1, z1 |
680 | local x2, y2, z2 |
681 | if bale.isRoundbale then |
682 | if bz >= -bale.width / 2 then |
683 | x1, y1, z1 = localToWorld(bale.nodeId, 0, 0, bale.width/2) |
684 | x2, y2, z2 = localToWorld(bale.nodeId, 0, 0, -bale.width/2) |
685 | end |
686 | else |
687 | if bx >= -bale.width / 2 then |
688 | x1, y1, z1 = localToWorld(bale.nodeId, bale.width/2, 0, 0) |
689 | x2, y2, z2 = localToWorld(bale.nodeId, -bale.width/2, 0, 0) |
690 | end |
691 | end |
692 | |
693 | if x1 ~= nil then |
694 | local distance = math.min(MathUtil.vector3Length(x-x1, y-y1, z-z1), MathUtil.vector3Length(x-x2, y-y2, z-z2)) |
695 | if distance < minDistance then |
696 | minDistance = distance |
697 | minBale = bale |
698 | end |
699 | end |
700 | end |
701 | end |
702 | end |
703 | |
704 | if minBale ~= nil then |
705 | local targetX, targetY, targetZ |
706 | if minBale.isRoundbale then |
707 | targetX, targetY, targetZ = self:updateRoundBaleWrappingNode(minBale, wrappingNode.node, x, y, z) |
708 | else |
709 | targetX, targetY, targetZ = self:updateSquareBaleWrappingNode(minBale, wrappingNode.node, x, y, z) |
710 | end |
711 | |
712 | if targetX ~= nil then |
713 | targetX, targetY, targetZ = worldToLocal(getParent(wrappingNode.target), targetX, targetY, targetZ) |
714 | setTranslation(wrappingNode.target, targetX, targetY, targetZ) |
715 | else |
716 | setTranslation(wrappingNode.target, wrappingNode.startTrans[1], wrappingNode.startTrans[2], wrappingNode.startTrans[3]) |
717 | end |
718 | else |
719 | setTranslation(wrappingNode.target, wrappingNode.startTrans[1], wrappingNode.startTrans[2], wrappingNode.startTrans[3]) |
720 | end |
721 | end |
722 | |
723 | spec.resetWrappingNodes = true |
724 | else |
725 | if spec.resetWrappingNodes then |
726 | for _, wrappingNode in ipairs(spec.wrappingNodes) do |
727 | setTranslation(wrappingNode.target, wrappingNode.startTrans[1], wrappingNode.startTrans[2], wrappingNode.startTrans[3]) |
728 | end |
729 | |
730 | spec.resetWrappingNodes = nil |
731 | end |
732 | end |
733 | end |