LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

FillVolume

Description
Specialization for visual fill volumes/planes; requires FillUnit specialization
Functions

getFillVolumeIndicesByFillUnitIndex

Description
Definition
getFillVolumeIndicesByFillUnitIndex()
Code
530function FillVolume:getFillVolumeIndicesByFillUnitIndex(fillUnitIndex)
531 local spec = self.spec_fillVolume
532 local indices = {}
533 for i, fillVolume in ipairs(spec.volumes) do
534 if fillVolume.fillUnitIndex == fillUnitIndex then
535 table.insert(indices, i)
536 end
537 end
538
539 return indices
540end

getFillVolumeLoadInfo

Description
Definition
getFillVolumeLoadInfo()
Code
516function FillVolume:getFillVolumeLoadInfo(loadInfoIndex)
517 local spec = self.spec_fillVolume
518 return spec.loadInfos[loadInfoIndex]
519end

getFillVolumeUnloadInfo

Description
Definition
getFillVolumeUnloadInfo()
Code
523function FillVolume:getFillVolumeUnloadInfo(unloadInfoIndex)
524 local spec = self.spec_fillVolume
525 return spec.unloadInfos[unloadInfoIndex]
526end

getFillVolumeUVScrollSpeed

Description
Definition
getFillVolumeUVScrollSpeed()
Code
564function FillVolume:getFillVolumeUVScrollSpeed()
565 return 0, 0, 0
566end

initSpecialization

Description
Definition
initSpecialization()
Code
56function FillVolume.initSpecialization()
57 g_configurationManager:addConfigurationType("fillVolume", g_i18n:getText("configuration_fillVolume"), "fillVolume", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
58end

loadFillVolume

Description
Definition
loadFillVolume()
Code
316function FillVolume:loadFillVolume(xmlFile, key, entry)
317 local spec = self.spec_fillVolume
318 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. "#index", key .. "#node") -- FS17
319
320 entry.baseNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#node"), self.i3dMappings)
321 if entry.baseNode == nil then
322 print("Warning: fillVolume '"..tostring(key).."' has an invalid 'node' in '"..self.configFileName.."'!")
323 return false
324 end
325
326 local fillUnitIndex = getXMLInt(xmlFile, key.."#fillUnitIndex")
327 entry.fillUnitIndex = fillUnitIndex
328 if fillUnitIndex == nil then
329 print("Warning: fillVolume '"..tostring(key).."' has no 'fillUnitIndex' given in '"..self.configFileName.."'!")
330 return false
331 end
332 if not self:getFillUnitExists(fillUnitIndex) then
333 print("Warning: fillVolume '"..tostring(key).."' has an invalid 'fillUnitIndex' in '"..self.configFileName.."'!")
334 return false
335 end
336
337 entry.fillUnitFactor = Utils.getNoNil(getXMLFloat(xmlFile, key.."#fillUnitFactor"), 1.0)
338
339 if spec.fillUnitFillVolumeMapping[fillUnitIndex] == nil then
340 spec.fillUnitFillVolumeMapping[fillUnitIndex] = {fillVolumes={}, sumFactors=0}
341 end
342 table.insert(spec.fillUnitFillVolumeMapping[fillUnitIndex].fillVolumes, entry)
343 spec.fillUnitFillVolumeMapping[fillUnitIndex].sumFactors = entry.fillUnitFactor
344
345 entry.allSidePlanes = Utils.getNoNil(getXMLBool(xmlFile, key .. "#allSidePlanes"), true)
346
347 local defaultFillTypeStr = getXMLString(xmlFile, key .. "#defaultFillType")
348 if defaultFillTypeStr ~= nil then
349 local defaultFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(defaultFillTypeStr)
350 if defaultFillTypeIndex == nil then
351 print("Warning: Invalid defaultFillType '"..tostring(defaultFillTypeStr).."' for '"..tostring(key).."' in '"..self.configFileName.."'")
352 return false
353 else
354 entry.defaultFillType = defaultFillTypeIndex
355 end
356 else
357 entry.defaultFillType = self:getFillUnitFirstSupportedFillType(fillUnitIndex)
358 end
359
360 local forcedVolumeFillTypeStr = getXMLString(xmlFile, key .. "#defaultFillType")
361 if forcedVolumeFillTypeStr ~= nil then
362 local forcedVolumeFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(forcedVolumeFillTypeStr)
363 if forcedVolumeFillTypeIndex ~= nil then
364 entry.forcedVolumeFillType = forcedVolumeFillTypeIndex
365 else
366 print("Warning: Invalid forcedVolumeFillType '"..tostring(forcedVolumeFillTypeStr).."' for '"..tostring(key).."' in '"..self.configFileName.."'")
367 return false
368 end
369 end
370
371 entry.maxDelta = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxDelta"), 1.0)
372 entry.maxSurfaceAngle = math.rad( Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxAllowedHeapAngle"), 35) )
373
374 entry.maxPhysicalSurfaceAngle = math.rad(35)
375 entry.maxSubDivEdgeLength = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxSubDivEdgeLength"), 0.9)
376
377 entry.uvPosition = {0, 0, 0}
378
379 entry.deformers = {}
380 local j = 0
381 while true do
382 local deformerKey = string.format("%s.deformNode(%d)", key, j)
383 if not hasXMLProperty(xmlFile, deformerKey) then
384 break
385 end
386
387 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, deformerKey .. "#index", deformerKey .. "#node") -- FS17
388
389 local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, deformerKey .. "#node"), self.i3dMappings)
390 if node ~= nil then
391 local initPos = {localToLocal(node, entry.baseNode, 0,0,0)}
392 local deformer = {node = node, initPos = initPos, posX = initPos[1], posZ = initPos[3], polyline = nil, volume = entry.volume, baseNode = entry.baseNode}
393 table.insert(entry.deformers, deformer)
394 spec.fillVolumeDeformersByNode[node] = deformer
395 end
396 j = j + 1
397 end
398
399 entry.lastFillType = FillType.UNKNOWN
400
401 return true
402end

loadFillVolumeHeightNode

Description
Definition
loadFillVolumeHeightNode()
Code
452function FillVolume:loadFillVolumeHeightNode(xmlFile, key, entry)
453 entry.isDirty = false
454
455 entry.fillVolumeIndex = getXMLInt(xmlFile, key.."#fillVolumeIndex") or 1
456
457 if self.spec_fillVolume.volumes[entry.fillVolumeIndex] == nil then
458 g_logManager:xmlWarning(self.configFileName, "Invalid fillVolumeIndex '%d' for heightNode '%s'. Igoring heightNode!", entry.fillVolumeIndex, key)
459 return false
460 end
461
462 entry.refNodes = {}
463 local i = 0
464 while true do
465 local nodeKey = key .. string.format(".refNode(%d)", i)
466 if not hasXMLProperty(xmlFile, nodeKey) then
467 break
468 end
469
470 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, nodeKey .. "#index", nodeKey .. "#node") -- FS17 to FS19
471
472 local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, nodeKey.."#node"), self.i3dMappings)
473 if node ~= nil then
474 table.insert(entry.refNodes, {refNode = node})
475 else
476 g_logManager:xmlWarning(self.configFileName, "Missing node for '%s'", nodeKey)
477 end
478
479 i = i + 1
480 end
481
482 entry.nodes = {}
483 i = 0
484 while true do
485 local nodeKey = key .. string.format(".node(%d)", i)
486 if not hasXMLProperty(xmlFile, nodeKey) then
487 break
488 end
489
490 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, nodeKey .. "#index", nodeKey .. "#node") -- FS17 to FS19
491
492 local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, nodeKey.."#node"), self.i3dMappings)
493 if node ~= nil then
494 local nodeEntry = {}
495 nodeEntry.node = node
496 nodeEntry.baseScale = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#baseScale"), "1 1 1")) }
497 nodeEntry.scaleAxis = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#scaleAxis"), "0 0 0")) }
498 nodeEntry.scaleMax = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#scaleMax"), "0 0 0")) }
499 nodeEntry.basePosition = { getTranslation(node) }
500 nodeEntry.transAxis = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#transAxis"), "0 0 0")) }
501 nodeEntry.transMax = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#transMax"), "0 0 0")) }
502 nodeEntry.orientateToWorldY = Utils.getNoNil(getXMLBool(xmlFile, nodeKey.."#orientateToWorldY"), false)
503 table.insert(entry.nodes, nodeEntry)
504 else
505 g_logManager:xmlWarning(self.configFileName, "Missing node for '%s'", nodeKey)
506 end
507
508 i = i + 1
509 end
510
511 return true
512end

loadFillVolumeInfo

Description
Definition
loadFillVolumeInfo()
Code
406function FillVolume:loadFillVolumeInfo(xmlFile, key, entry)
407 entry.nodes = {}
408 local i = 0
409 while true do
410 local infoKey = key .. string.format(".node(%d)", i)
411 if not hasXMLProperty(xmlFile, infoKey) then
412 break
413 end
414
415 XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, infoKey .. "#index", infoKey .. "#node") -- FS17 to FS19
416
417 local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, infoKey .. "#node"), self.i3dMappings)
418 if node ~= nil then
419 local nodeEntry = {}
420
421 nodeEntry.node = node
422 nodeEntry.width = Utils.getNoNil(getXMLFloat(xmlFile, infoKey .. "#width"), 1.0)
423 nodeEntry.length = Utils.getNoNil(getXMLFloat(xmlFile, infoKey .. "#length"), 1.0)
424
425 nodeEntry.fillVolumeHeightIndex = getXMLInt(xmlFile, infoKey .. "#fillVolumeHeightIndex")
426 nodeEntry.priority = Utils.getNoNil(getXMLInt(xmlFile, infoKey .. "#priority"), 1)
427 nodeEntry.minHeight = getXMLFloat(xmlFile, infoKey .. "#minHeight")
428 nodeEntry.maxHeight = getXMLFloat(xmlFile, infoKey .. "#maxHeight")
429 nodeEntry.minFillLevelPercentage = getXMLFloat(xmlFile, infoKey .. "#minFillLevelPercentage")
430 nodeEntry.maxFillLevelPercentage = getXMLFloat(xmlFile, infoKey .. "#maxFillLevelPercentage")
431
432 nodeEntry.heightForTranslation = getXMLFloat(xmlFile, infoKey .. "#heightForTranslation")
433 nodeEntry.translationStart = StringUtil.getVectorNFromString(getXMLString(xmlFile, infoKey .. "#translationStart"), 3)
434 nodeEntry.translationEnd = StringUtil.getVectorNFromString(getXMLString(xmlFile, infoKey .. "#translationEnd"), 3)
435 nodeEntry.translationAlpha = 0
436
437 table.insert(entry.nodes, nodeEntry)
438 else
439 g_logManager:xmlWarning(self.configFileName, "Missing node for '%s'", infoKey)
440 end
441
442 i = i + 1
443 end
444
445 table.sort(entry.nodes, function(a, b) return a.priority > b.priority end)
446
447 return true
448end

onDelete

Description
Definition
onDelete()
Code
170function FillVolume:onDelete()
171 local spec = self.spec_fillVolume
172 for _, fillVolume in ipairs(spec.volumes) do
173 if fillVolume.volume ~= nil then
174 delete(fillVolume.volume)
175 end
176 fillVolume.volume = nil
177 end
178end

onFillUnitFillLevelChanged

Description
Definition
onFillUnitFillLevelChanged()
Code
584function FillVolume:onFillUnitFillLevelChanged(fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta)
585 local spec = self.spec_fillVolume
586
587 local mapping = spec.fillUnitFillVolumeMapping[fillUnitIndex]
588 if mapping == nil then
589 return
590 end
591
592 local fillLevel = self:getFillUnitFillLevel(fillUnitIndex)
593
594 fillType = self:getFillUnitFillType(fillUnitIndex)
595
596 for _, volume in ipairs(mapping.fillVolumes) do
597 local baseNode = volume.baseNode
598 local volumeNode = volume.volume
599 if baseNode == nil or volumeNode == nil then
600 return
601 end
602
603 if volume.forcedFillType ~= nil then
604 fillType = volume.forcedFillType
605 end
606 if fillLevel == 0 then
607 volume.forcedFillType = nil
608 end
609
610 if fillType ~= volume.lastFillType then
611 local maxPhysicalSurfaceAngle
612 local fillType = g_fillTypeManager:getFillTypeByIndex(fillType)
613 if fillType ~= nil then
614 maxPhysicalSurfaceAngle = fillType.maxPhysicalSurfaceAngle
615 end
616 if maxPhysicalSurfaceAngle ~= nil then
617 if volume.volume ~= nil then
618 setFillPlaneMaxPhysicalSurfaceAngle(volume.volume, maxPhysicalSurfaceAngle)
619 end
620 end
621 end
622
623 setVisibility(volume.volume, fillLevel > 0)
624
625 local material = nil
626 if fillType ~= FillType.UNKNOWN and fillType ~= volume.lastFillType then
627 local usedFillType = fillType
628 if volume.forcedVolumeFillType ~= nil then
629 usedFillType = volume.forcedVolumeFillType
630 end
631 material = g_materialManager:getMaterial(usedFillType, "fillplane", 1)
632 end
633
634 if fillType ~= FillType.UNKNOWN and fillType ~= volume.lastFillType then
635 if material == nil and volume.defaultFillType ~= nil then
636 material = g_materialManager:getMaterial(volume.defaultFillType, "fillplane", 1)
637 end
638
639 if material ~= nil then
640 setMaterial(volume.volume, material, 0)
641 end
642 end
643
644 if fillPositionData ~= nil then
645 local availableFillNodes = {}
646
647 if fillPositionData.nodes ~= nil then
648 local neededPriority = fillPositionData.nodes[1].priority
649
650 while table.getn(availableFillNodes) == 0 and neededPriority >= 1 do
651
652 for _,node in pairs(fillPositionData.nodes) do
653 if node.priority >= neededPriority then
654 local doInsert = true
655
656 if node.minHeight ~= nil or node.maxHeight ~= nil then
657
658 local height = -math.huge
659 if node.fillVolumeHeightIndex ~= nil and spec.heightNodes[node.fillVolumeHeightIndex] ~= nil then
660 for _,refNode in pairs(spec.heightNodes[node.fillVolumeHeightIndex].refNodes) do
661 local x,_,z = localToLocal(refNode.refNode, baseNode, 0,0,0)
662 height = math.max(height, getFillPlaneHeightAtLocalPos(volumeNode, x,z))
663 end
664 else
665 local x,_,z = localToLocal(node.node, baseNode, 0,0,0)
666 height = math.max(height, getFillPlaneHeightAtLocalPos(volumeNode, x,z))
667 end
668
669 if node.minHeight ~= nil and height < node.minHeight then
670 doInsert = false
671 end
672 if node.maxHeight ~= nil and height > node.maxHeight then
673 doInsert = false
674 end
675
676 if node.heightForTranslation ~= nil then
677 if height > node.heightForTranslation then
678 node.translationAlpha = node.translationAlpha + 0.01
679 local x,y,z = MathUtil.vector3ArrayLerp(node.translationStart, node.translationEnd, node.translationAlpha)
680 setTranslation(node.node, x,y,z)
681 else
682 node.translationAlpha = node.translationAlpha - 0.01
683 end
684 node.translationAlpha = MathUtil.clamp(node.translationAlpha, 0, 1)
685 end
686
687 end
688
689 if node.minFillLevelPercentage ~= nil or node.maxFillLevelPercentage ~= nil then
690 local percentage = fillLevel / self:getFillUnitCapacity(fillUnitIndex)
691
692 if node.minFillLevelPercentage ~= nil and percentage < node.minFillLevelPercentage then
693 doInsert = false
694 end
695 if node.maxFillLevelPercentage ~= nil and percentage > node.maxFillLevelPercentage then
696 doInsert = false
697 end
698 end
699
700 if doInsert then
701 table.insert(availableFillNodes, node)
702 end
703 end
704 end
705 if table.getn(availableFillNodes) > 0 then
706 break
707 end
708 neededPriority = neededPriority - 1
709 end
710 else
711 table.insert(availableFillNodes, fillPositionData)
712 end
713
714 local numFillNodes = table.getn(availableFillNodes)
715
716 local avgX, avgZ = 0, 0
717
718 for i=1,numFillNodes do
719 local node = availableFillNodes[i]
720
721 local x0,y0,z0 = getWorldTranslation(node.node)
722 local d1x,d1y,d1z = localDirectionToWorld(node.node, node.width,0,0)
723 local d2x,d2y,d2z = localDirectionToWorld(node.node, 0,0,node.length)
724
725 if VehicleDebug.state == VehicleDebug.DEBUG then
726 drawDebugLine( x0,y0,z0, 1,0,0, x0+d1x, y0+d1y, z0+d1z, 1,0,0 )
727 drawDebugLine( x0,y0,z0, 0,0,1, x0+d2x, y0+d2y, z0+d2z, 0,0,1 )
728 drawDebugPoint( x0,y0,z0, 1,1,1,1 )
729 drawDebugPoint( x0+d1x, y0+d1y, z0+d1z, 1,0,0,1 )
730 drawDebugPoint( x0+d2x, y0+d2y, z0+d2z, 0,0,1,1 )
731 end
732 x0 = x0 - (d1x + d2x) / 2
733 y0 = y0 - (d1y + d2y) / 2
734 z0 = z0 - (d1z + d2z) / 2
735 fillPlaneAdd(volume.volume, appliedDelta/numFillNodes, x0,y0,z0, d1x,d1y,d1z, d2x,d2y,d2z)
736
737 local newX, _, newZ = localToLocal(node.node, volume.volume, 0, 0, 0)
738 avgX, avgZ = avgX+newX, avgZ+newZ
739 end
740
741 local newX = avgX / numFillNodes
742 local newZ = avgZ / numFillNodes
743 if math.abs(newX-spec.lastPositionInfoSent[1]) > FillVolume.SEND_PRECISION or math.abs(newZ-spec.lastPositionInfoSent[2]) > FillVolume.SEND_PRECISION then
744 spec.lastPositionInfoSent[1] = newX
745 spec.lastPositionInfoSent[2] = newZ
746
747 self:raiseDirtyFlags(spec.dirtyFlag)
748 end
749 else
750 local x,y,z = localToWorld(volume.volume, 0,0,0)
751 local d1x,d1y,d1z = localDirectionToWorld(volume.volume, 0.1,0,0)
752 local d2x,d2y,d2z = localDirectionToWorld(volume.volume, 0,0,0.1)
753
754 if not self.isServer then
755 if spec.lastPositionInfo[1] ~= 0 and spec.lastPositionInfo[2] ~= 0 then
756 x, y, z = localToWorld(volume.volume, spec.lastPositionInfo[1], 0, spec.lastPositionInfo[2])
757 end
758 end
759
760 local steps = MathUtil.clamp(math.floor(appliedDelta/400), 1, 25)
761 for i=1, steps do
762 fillPlaneAdd(volume.volume, appliedDelta/steps, x,y,z, d1x,d1y,d1z, d2x,d2y,d2z)
763 end
764 end
765
766 local heightNodes = spec.fillVolumeIndexToHeightNode[volume.index]
767 if heightNodes ~= nil then
768 for _, heightNode in ipairs(heightNodes) do
769 heightNode.isDirty = true
770 end
771 end
772
773 for _,deformer in pairs(volume.deformers) do
774 deformer.isDirty = true
775 end
776
777 volume.lastFillType = fillType
778 end
779end

onLoad

Description
Definition
onLoad()
Code
62function FillVolume:onLoad(savegame)
63 local spec = self.spec_fillVolume
64
65 local fillVolumeConfigurationId = Utils.getNoNil(self.configurations["fillVolume"], 1)
66 local configKey = string.format("vehicle.fillVolume.fillVolumeConfigurations.fillVolumeConfiguration(%d).volumes", fillVolumeConfigurationId -1)
67 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.fillVolume.fillVolumeConfigurations.fillVolumeConfiguration", fillVolumeConfigurationId , self.components, self)
68
69 spec.volumes = {}
70 spec.fillVolumeDeformersByNode = {}
71 spec.fillUnitFillVolumeMapping = {}
72 local i = 0
73 while true do
74 local key = string.format("%s.volume(%d)", configKey, i)
75 if not hasXMLProperty(self.xmlFile, key) then
76 break
77 end
78 local entry = {}
79 if self:loadFillVolume(self.xmlFile, key, entry) then
80 table.insert(spec.volumes, entry)
81 entry.index = #spec.volumes
82 end
83 i = i + 1
84 end
85
86 -- create fill units
87 for _, mapping in ipairs(spec.fillUnitFillVolumeMapping) do
88 for _, fillVolume in ipairs(mapping.fillVolumes) do
89 fillVolume.fillUnitFactor = fillVolume.fillUnitFactor / mapping.sumFactors
90 end
91 end
92
93 for _, fillVolume in ipairs(spec.volumes) do
94 local capacity = self:getFillUnitCapacity(fillVolume.fillUnitIndex)
95 local fillVolumeCapacity = capacity * fillVolume.fillUnitFactor
96 fillVolume.volume = createFillPlaneShape(fillVolume.baseNode, "fillPlane", fillVolumeCapacity, fillVolume.maxDelta, fillVolume.maxSurfaceAngle, fillVolume.maxPhysicalSurfaceAngle, fillVolume.maxSubDivEdgeLength, fillVolume.allSidePlanes)
97 if fillVolume.volume == nil or fillVolume.volume == 0 then
98 print("Warning: fillVolume '"..tostring(getName(fillVolume.baseNode)).."' could not create actual fillVolume in '"..self.configFileName.."'! Simplifying the mesh could help")
99 else
100 setVisibility(fillVolume.volume, false)
101
102 for i=#fillVolume.deformers, 1, -1 do
103 local deformer = fillVolume.deformers[i]
104 deformer.polyline = findPolyline(fillVolume.volume, deformer.posX, deformer.posZ)
105 if deformer.polyline == nil and deformer.polyline ~= -1 then
106 print("Warning: Could not find 'polyline' for '"..tostring(getName(deformer.node)).."' in '"..self.configFileName.."'")
107 table.remove(fillVolume.deformers, i)
108 end
109 end
110
111 link(fillVolume.baseNode, fillVolume.volume)
112 end
113 end
114
115 spec.loadInfos = {}
116 local i = 0
117 while true do
118 local key = string.format("vehicle.fillVolume.loadInfos.loadInfo(%d)", i)
119 if not hasXMLProperty(self.xmlFile, key) then
120 break
121 end
122 local entry = {}
123 if self:loadFillVolumeInfo(self.xmlFile, key, entry) then
124 table.insert(spec.loadInfos, entry)
125 end
126 i = i + 1
127 end
128
129 spec.unloadInfos = {}
130 local i = 0
131 while true do
132 local key = string.format("vehicle.fillVolume.unloadInfos.unloadInfo(%d)", i)
133 if not hasXMLProperty(self.xmlFile, key) then
134 break
135 end
136 local entry = {}
137 if self:loadFillVolumeInfo(self.xmlFile, key, entry) then
138 table.insert(spec.unloadInfos, entry)
139 end
140 i = i + 1
141 end
142
143 spec.heightNodes = {}
144 spec.fillVolumeIndexToHeightNode = {}
145 local i = 0
146 while true do
147 local key = string.format("vehicle.fillVolume.heightNodes.heightNode(%d)", i)
148 if not hasXMLProperty(self.xmlFile, key) then
149 break
150 end
151 local entry = {}
152 if self:loadFillVolumeHeightNode(self.xmlFile, key, entry) then
153 table.insert(spec.heightNodes, entry)
154
155 if spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex] == nil then
156 spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex] = {}
157 end
158 table.insert(spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex], entry)
159 end
160 i = i + 1
161 end
162
163 spec.lastPositionInfo = {0, 0}
164 spec.lastPositionInfoSent = {0, 0}
165 spec.dirtyFlag = self:getNextDirtyFlag()
166end

onReadUpdateStream

Description
Definition
onReadUpdateStream()
Code
182function FillVolume:onReadUpdateStream(streamId, timestamp, connection)
183 if connection:getIsServer() then
184 local spec = self.spec_fillVolume
185
186 if streamReadBool(streamId) then
187 local x = (streamReadUIntN(streamId, FillVolume.SEND_NUM_BITS) / (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) * FillVolume.SEND_MAX_SIZE) - FillVolume.SEND_MAX_SIZE * 0.5
188 local z = (streamReadUIntN(streamId, FillVolume.SEND_NUM_BITS) / (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) * FillVolume.SEND_MAX_SIZE) - FillVolume.SEND_MAX_SIZE * 0.5
189
190 spec.lastPositionInfo[1] = x
191 spec.lastPositionInfo[2] = z
192 end
193 end
194end

onUpdate

Description
Definition
onUpdate()
Code
217function FillVolume:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
218 if self.isClient then
219 local spec = self.spec_fillVolume
220
221 -- deform (fill)volume
222 for _,volume in pairs(spec.volumes) do
223 for _,deformer in ipairs(volume.deformers) do
224 if deformer.isDirty and deformer.polyline ~= nil and deformer.polyline ~= -1 then
225 deformer.isDirty = false
226 local posX, _, posZ = localToLocal(deformer.node, deformer.baseNode, 0,0,0)
227 if math.abs(posX - deformer.posX) > 0.0001 or math.abs(posZ - deformer.posZ) > 0.0001 then
228 deformer.lastPosX = posX
229 deformer.lastPosZ = posZ
230 local dx = posX - deformer.initPos[1]
231 local dz = posZ - deformer.initPos[3]
232 setPolylineTranslation(volume.volume, deformer.polyline, dx,dz)
233 end
234 end
235 end
236
237 local uvScrollSpeedX, uvScrollSpeedY, uvScrollSpeedZ = self:getFillVolumeUVScrollSpeed(volume.index)
238 if uvScrollSpeedX ~= 0 or uvScrollSpeedY ~= 0 or uvScrollSpeedZ ~= 0 then
239 volume.uvPosition[1] = volume.uvPosition[1] + uvScrollSpeedX*dt
240 volume.uvPosition[2] = volume.uvPosition[2] + uvScrollSpeedY*dt
241 volume.uvPosition[3] = volume.uvPosition[3] + uvScrollSpeedZ*dt
242 setShaderParameter(volume.volume, "uvOffset", volume.uvPosition[1], volume.uvPosition[2], volume.uvPosition[3], 0, false)
243 end
244 end
245
246 -- update heightNodes
247 for _,heightNode in pairs(spec.heightNodes) do
248 if heightNode.isDirty then
249 heightNode.isDirty = false
250
251 local baseNode = spec.volumes[heightNode.fillVolumeIndex].baseNode
252 local volumeNode = spec.volumes[heightNode.fillVolumeIndex].volume
253
254 if baseNode ~= nil and volumeNode ~= nil then
255
256 local minHeight = math.huge
257 local maxHeight = -math.huge
258 local maxHeightWorld = -math.huge
259 for _,refNode in pairs(heightNode.refNodes) do
260 local x,_,z = localToLocal(refNode.refNode, baseNode, 0,0,0)
261 local height = getFillPlaneHeightAtLocalPos(volumeNode, x,z)
262 minHeight = math.min(minHeight, height)
263 maxHeight = math.max(maxHeight, height)
264 local _,yw,_ = localToWorld(baseNode, x,height,z)
265 maxHeightWorld = math.max(maxHeightWorld, yw)
266 end
267
268 heightNode.currentMinHeight = minHeight
269 heightNode.currentMaxHeight = maxHeight
270 heightNode.currentMaxHeightWorld = maxHeightWorld
271
272 for _,node in pairs(heightNode.nodes) do
273
274 local sx = node.scaleAxis[1]*minHeight
275 local sy = node.scaleAxis[2]*minHeight
276 local sz = node.scaleAxis[3]*minHeight
277 if node.scaleMax[1] > 0 then
278 sx = math.min(node.scaleMax[1], sx)
279 end
280 if node.scaleMax[2] > 0 then
281 sy = math.min(node.scaleMax[2], sy)
282 end
283 if node.scaleMax[3] > 0 then
284 sz = math.min(node.scaleMax[3], sz)
285 end
286 local tx = node.transAxis[1]*minHeight
287 local ty = node.transAxis[2]*minHeight
288 local tz = node.transAxis[3]*minHeight
289 if node.transMax[1] > 0 then
290 tx = math.min(node.transMax[1], tx)
291 end
292 if node.transMax[2] > 0 then
293 ty = math.min(node.transMax[2], ty)
294 end
295 if node.transMax[3] > 0 then
296 tz = math.min(node.transMax[3], tz)
297 end
298
299 setScale(node.node, node.baseScale[1]+sx, node.baseScale[2]+sy, node.baseScale[3]+sz)
300 setTranslation(node.node, node.basePosition[1]+tx, node.basePosition[2]+ty, node.basePosition[3]+tz)
301
302 if node.orientateToWorldY then
303 local _,dy,_ = localDirectionToWorld(getParent(node.node), 0,1,0)
304 local alpha = math.acos(dy)
305 setRotation(node.node, alpha,0,0)
306 end
307 end
308 end
309 end
310 end
311 end
312end

onWriteUpdateStream

Description
Definition
onWriteUpdateStream()
Code
198function FillVolume:onWriteUpdateStream(streamId, connection, dirtyMask)
199 if not connection:getIsServer() then
200 local spec = self.spec_fillVolume
201
202 if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then
203 local x = (spec.lastPositionInfoSent[1] + FillVolume.SEND_MAX_SIZE * 0.5) / FillVolume.SEND_MAX_SIZE * (math.pow(2, FillVolume.SEND_NUM_BITS) - 1)
204 streamWriteUIntN(streamId, x, FillVolume.SEND_NUM_BITS)
205
206 local z = (spec.lastPositionInfoSent[2] + FillVolume.SEND_MAX_SIZE * 0.5) / FillVolume.SEND_MAX_SIZE * (math.pow(2, FillVolume.SEND_NUM_BITS) - 1)
207 streamWriteUIntN(streamId, z, FillVolume.SEND_NUM_BITS)
208
209 spec.lastPositionInfoSent[1] = (math.floor(x) / (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) * FillVolume.SEND_MAX_SIZE) - FillVolume.SEND_MAX_SIZE * 0.5
210 spec.lastPositionInfoSent[2] = (math.floor(z) / (math.pow(2, FillVolume.SEND_NUM_BITS) - 1) * FillVolume.SEND_MAX_SIZE) - FillVolume.SEND_MAX_SIZE * 0.5
211 end
212 end
213end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
19function FillVolume.prerequisitesPresent(specializations)
20 return SpecializationUtil.hasSpecialization(FillUnit, specializations)
21end

registerEventListeners

Description
Definition
registerEventListeners()
Code
45function FillVolume.registerEventListeners(vehicleType)
46 SpecializationUtil.registerEventListener(vehicleType, "onLoad", FillVolume)
47 SpecializationUtil.registerEventListener(vehicleType, "onDelete", FillVolume)
48 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", FillVolume)
49 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", FillVolume)
50 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", FillVolume)
51 SpecializationUtil.registerEventListener(vehicleType, "onFillUnitFillLevelChanged", FillVolume)
52end

registerFunctions

Description
Definition
registerFunctions()
Code
25function FillVolume.registerFunctions(vehicleType)
26 SpecializationUtil.registerFunction(vehicleType, "loadFillVolume", FillVolume.loadFillVolume)
27 SpecializationUtil.registerFunction(vehicleType, "loadFillVolumeInfo", FillVolume.loadFillVolumeInfo)
28 SpecializationUtil.registerFunction(vehicleType, "loadFillVolumeHeightNode", FillVolume.loadFillVolumeHeightNode)
29 SpecializationUtil.registerFunction(vehicleType, "getFillVolumeLoadInfo", FillVolume.getFillVolumeLoadInfo)
30 SpecializationUtil.registerFunction(vehicleType, "getFillVolumeUnloadInfo", FillVolume.getFillVolumeUnloadInfo)
31 SpecializationUtil.registerFunction(vehicleType, "getFillVolumeIndicesByFillUnitIndex", FillVolume.getFillVolumeIndicesByFillUnitIndex)
32 SpecializationUtil.registerFunction(vehicleType, "setFillVolumeForcedFillTypeByFillUnitIndex", FillVolume.setFillVolumeForcedFillTypeByFillUnitIndex)
33 SpecializationUtil.registerFunction(vehicleType, "setFillVolumeForcedFillType", FillVolume.setFillVolumeForcedFillType)
34 SpecializationUtil.registerFunction(vehicleType, "getFillVolumeUVScrollSpeed", FillVolume.getFillVolumeUVScrollSpeed)
35end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
39function FillVolume.registerOverwrittenFunctions(vehicleType)
40 SpecializationUtil.registerOverwrittenFunction(vehicleType, "setMovingToolDirty", FillVolume.setMovingToolDirty)
41end

setFillVolumeForcedFillType

Description
Definition
setFillVolumeForcedFillType()
Code
555function FillVolume:setFillVolumeForcedFillType(fillVolumeIndex, forcedFillType)
556 local spec = self.spec_fillVolume
557 if spec.volumes[fillVolumeIndex] ~= nil then
558 spec.volumes[fillVolumeIndex].forcedFillType = forcedFillType
559 end
560end

setFillVolumeForcedFillTypeByFillUnitIndex

Description
Definition
setFillVolumeForcedFillTypeByFillUnitIndex()
Code
544function FillVolume:setFillVolumeForcedFillTypeByFillUnitIndex(fillUnitIndex, forcedFillType)
545 local spec = self.spec_fillVolume
546 for i, fillVolume in ipairs(spec.volumes) do
547 if fillVolume.fillUnitIndex == fillUnitIndex then
548 self:setFillVolumeForcedFillType(i, forcedFillType)
549 end
550 end
551end

setMovingToolDirty

Description
Definition
setMovingToolDirty()
Code
570function FillVolume:setMovingToolDirty(superFunc, node)
571 superFunc(self, node)
572
573 local spec = self.spec_fillVolume
574 if spec.fillVolumeDeformersByNode ~= nil then
575 local deformer = spec.fillVolumeDeformersByNode[node]
576 if deformer ~= nil then
577 deformer.isDirty = true
578 end
579 end
580end