LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

TreePlantManager

Parent
AbstractManager
Functions

addClientTree

Description
Definition
addClientTree()
Code
720function TreePlantManager:addClientTree(serverSplitShapeFileId, nodeId)
721 if self.treesData ~= nil then
722 self.treesData.clientTrees[serverSplitShapeFileId] = nodeId
723 end
724end

addingSplitShape

Description
Definition
addingSplitShape()
Code
748function TreePlantManager:addingSplitShape(shape, oldShape, fromTree)
749 local state
750 local variation
751
752 -- If a parent is provided, copy the info if we still actively update
753 if oldShape ~= nil and self.activeDecayingSplitShapes[oldShape] ~= nil then
754 state = self.activeDecayingSplitShapes[oldShape].state
755 variation = self.activeDecayingSplitShapes[oldShape].variation
756 elseif fromTree then
757 state = 1
758 local x, y, z = getWorldTranslation(shape)
759 variation = x + y + z
760 else
761 state = 0
762 variation = 80
763 end
764
765 -- With no children, the shape has no branches and we need to update nothing
766 -- And as cuts from this item cannot have branches either, we do not need to store
767 -- it for parent state either.
768 if state ~= nil and getNumOfChildren(shape) > 0 then
769 self.activeDecayingSplitShapes[shape] = {state=state, variation=variation}
770
771 self:setSplitShapeLeafScaleAndVariation(shape, state, variation)
772 end
773
774 g_messageCenter:publish(MessageType.TREE_SHAPE_CUT, oldShape, shape)
775end

addTreeCutJoint

Description
Definition
addTreeCutJoint()
Code
482function TreePlantManager:addTreeCutJoint(jointIndex, shape, nx,ny,nz, maxAngle, maxLifetime)
483 local treesData = self.treesData
484 local lnx,lny,lnz = worldDirectionToLocal(shape, nx,ny,nz)
485 local joint = {jointIndex=jointIndex, shape=shape, nx=nx,ny=ny,nz=nz, lnx=lnx,lny=lny,lnz=lnz, maxCosAngle=math.cos(maxAngle), destroyTime=g_currentMission.time+maxLifetime}
486 treesData.treeCutJoints[joint] = joint
487end

canPlantTree

Description
Definition
canPlantTree()
Code
178function TreePlantManager:canPlantTree()
179 local totalNumSplit, numSplit = getNumOfSplitShapes()
180 local numUnsplit = totalNumSplit - numSplit
181 return (numUnsplit + self.numTreesWithoutSplits) < TreePlantManager.MAX_NUM_OF_SPLITSHAPES
182end

cleanupDeletedTrees

Description
Definition
cleanupDeletedTrees()
Code
491function TreePlantManager:cleanupDeletedTrees()
492 local treesData = self.treesData
493
494 local numGrowingTrees = #treesData.growingTrees
495 local i = 1
496 while i<=numGrowingTrees do
497 local tree = treesData.growingTrees[i]
498 -- Check if the tree has been cut in the mean time
499 if getNumOfChildren(tree.node) == 0 then
500 -- The tree has been removed completely, remove from list
501 table.remove(treesData.growingTrees, i)
502 numGrowingTrees = numGrowingTrees-1
503 delete(tree.node)
504
505 if not tree.hasSplitShapes then
506 self.numTreesWithoutSplits = math.max(self.numTreesWithoutSplits - 1, 0)
507 treesData.numTreesWithoutSplits = math.max(treesData.numTreesWithoutSplits - 1, 0)
508 end
509 else
510 i = i+1
511 end
512 end
513 local numSplitTrees = #treesData.splitTrees
514 local i = 1
515 while i<=numSplitTrees do
516 local tree = treesData.splitTrees[i]
517 -- Check if the tree has been cut in the mean time
518 if getNumOfChildren(tree.node) == 0 then
519 -- The tree has been removed completely, remove from list
520 table.remove(treesData.splitTrees, i)
521 numSplitTrees = numSplitTrees-1
522 delete(tree.node)
523
524 if not tree.hasSplitShapes then
525 self.numTreesWithoutSplits = math.max(self.numTreesWithoutSplits - 1, 0)
526 treesData.numTreesWithoutSplits = math.max(treesData.numTreesWithoutSplits - 1, 0)
527 end
528 else
529 i = i+1
530 end
531 end
532end

cutTreeTrunkCallback

Description
Definition
cutTreeTrunkCallback()
Code
302function TreePlantManager:cutTreeTrunkCallback(shape, isBelow, isAbove, minY, maxY, minZ, maxZ)
303 self:addingSplitShape(shape, self.shapeBeingCut)
304 table.insert(self.loadTreeTrunkData.parts, {shape=shape, isBelow=isBelow, isAbove=isAbove, minY=minY, maxY=maxY, minZ=minZ, maxZ=maxZ})
305end

deleteTreesData

Description
Definition
deleteTreesData()
Code
57function TreePlantManager:deleteTreesData()
58 if self.treesData ~= nil then
59 delete(self.treesData.rootNode)
60 self.numTreesWithoutSplits = math.max(self.numTreesWithoutSplits - self.treesData.numTreesWithoutSplits, 0)
61 self:initDataStructures()
62 end
63end

getClientTree

Description
Definition
getClientTree()
Code
736function TreePlantManager:getClientTree(serverSplitShapeFileId)
737 if self.treesData ~= nil then
738 return self.treesData.clientTrees[serverSplitShapeFileId]
739 end
740end

getTreeTypeDescFromIndex

Description
Definition
getTreeTypeDescFromIndex()
Code
701function TreePlantManager:getTreeTypeDescFromIndex(index)
702 if self.treeTypes ~= nil then
703 return self.treeTypes[index]
704 end
705 return nil
706end

getTreeTypeDescFromName

Description
Definition
getTreeTypeDescFromName()
Code
710function TreePlantManager:getTreeTypeDescFromName(name)
711 if self.nameToTreeType ~= nil and name ~= nil then
712 name = name:upper()
713 return self.nameToTreeType[name]
714 end
715 return nil
716end

getTreeTypeFilename

Description
Definition
getTreeTypeFilename()
Code
168function TreePlantManager:getTreeTypeFilename(treeTypeDesc, growthState)
169 if treeTypeDesc == nil then
170 return nil
171 end
172
173 return treeTypeDesc.treeFilenames[math.min(growthState, #treeTypeDesc.treeFilenames)]
174end

initDataStructures

Description
Definition
initDataStructures()
Code
27function TreePlantManager:initDataStructures()
28 self.treeTypes = {}
29 self.indexToTreeType = {}
30 self.nameToTreeType = {}
31 self.treeFileCache = {}
32
33 self.numTreesWithoutSplits = 0
34
35 self.activeDecayingSplitShapes = {}
36 self.updateDecayDtGame = 0
37end

initialize

Description
Definition
initialize()
Code
41function TreePlantManager:initialize()
42 local rootNode = createTransformGroup("trees")
43 link(getRootNode(), rootNode)
44
45 self.treesData = {}
46 self.treesData.rootNode = rootNode
47 self.treesData.growingTrees = {}
48 self.treesData.splitTrees = {}
49 self.treesData.clientTrees = {}
50 self.treesData.updateDtGame = 0
51 self.treesData.treeCutJoints = {}
52 self.treesData.numTreesWithoutSplits = 0
53end

loadDefaultTypes

Description
Definition
loadDefaultTypes()
Code
67function TreePlantManager:loadDefaultTypes(missionInfo, baseDirectory)
68 local xmlFile = loadXMLFile("treeTypes", "data/maps/maps_treeTypes.xml")
69 self:loadTreeTypes(xmlFile, missionInfo, baseDirectory, true)
70 delete(xmlFile)
71end

loadFromXMLFile

Description
Definition
loadFromXMLFile()
Code
536function TreePlantManager:loadFromXMLFile(xmlFilename)
537 if xmlFilename == nil then
538 return false
539 end
540 local xmlFile = loadXMLFile("treePlantXML", xmlFilename)
541 if xmlFile == 0 then
542 return false
543 end
544
545 local i = 0
546 while true do
547
548 local key = string.format("treePlant.tree(%d)", i)
549 if not hasXMLProperty(xmlFile, key) then
550 break
551 end
552
553 local x, y, z = string.getVector(getXMLString(xmlFile, key.."#position"))
554 local rx, ry, rz = string.getVector(getXMLString(xmlFile, key.."#rotation"))
555
556 rx = math.rad(rx)
557 ry = math.rad(ry)
558 rz = math.rad(rz)
559
560 local treeTypeName = getXMLString(xmlFile, key.."#treeType")
561 local treeType = self.nameToTreeType[treeTypeName]
562
563 if x ~= nil and y ~= nil and z ~= nil and rx ~= nil and ry ~= nil and rz ~= nil and treeType ~= nil then
564 local growthState = Utils.getNoNil(getXMLFloat(xmlFile, key.."#growthState"), 0.0)
565 local isGrowing = Utils.getNoNil(getXMLBool(xmlFile, key.."#isGrowing"), true)
566 local growthStateI = getXMLInt(xmlFile, key.."#growthStateI") -- note: might be nil, plantTree will use default behaviour (calculate from float growthState)
567 local splitShapeFileId = getXMLInt(xmlFile, key.."#splitShapeFileId") -- note: might be nil if not available
568 self:plantTree(treeType.index, x,y,z, rx,ry,rz, growthState, growthStateI, isGrowing, splitShapeFileId)
569 end
570
571 i = i + 1
572 end
573 delete(xmlFile)
574
575 return true
576end

loadMapData

Description
Load data on map load
Definition
loadMapData()
Return Values
booleantrueif loading was successful else false
Code
76function TreePlantManager:loadMapData(xmlFile, missionInfo, baseDirectory)
77 TreePlantManager:superClass().loadMapData(self)
78
79 self:loadDefaultTypes(missionInfo, baseDirectory)
80 return XMLUtil.loadDataFromMapXML(xmlFile, "treeTypes", baseDirectory, self, self.loadTreeTypes, missionInfo, baseDirectory)
81end

loadTreeNode

Description
Definition
loadTreeNode()
Code
229function TreePlantManager:loadTreeNode(treeTypeDesc, x,y,z, rx,ry,rz, growthStateI, splitShapeLoadingFileId)
230 local treesData = self.treesData
231
232 growthStateI = math.min(growthStateI, table.getn(treeTypeDesc.treeFilenames))
233 local i3dFilename = treeTypeDesc.treeFilenames[growthStateI]
234
235 if self.treeFileCache[i3dFilename] == nil then
236 -- make sure the i3d is loaded, so that the file id will not be used by the i3d clone source
237 setSplitShapesLoadingFileId(-1)
238 setSplitShapesNextFileId(true)
239 local node, requestId = g_i3DManager:loadSharedI3DFile(i3dFilename, false, false)
240 if node ~= 0 then
241 delete(node)
242 self.treeFileCache[i3dFilename] = requestId
243 end
244 end
245
246 setSplitShapesLoadingFileId(Utils.getNoNil(splitShapeLoadingFileId, -1))
247 local splitShapeFileId = setSplitShapesNextFileId()
248
249 local treeId, requestId = g_i3DManager:loadSharedI3DFile(i3dFilename, false, false)
250 g_i3DManager:releaseSharedI3DFile(requestId)
251
252 if treeId ~= 0 then
253 link(treesData.rootNode, treeId)
254
255 setTranslation(treeId, x,y,z)
256 setRotation(treeId, rx,ry,rz)
257 -- Split shapes loaded from savegames/streams are placed at world space, so correct the position after we moved our node
258 local numChildren = getNumOfChildren(treeId)
259 for i=0, numChildren-1 do
260 local child = getChildAt(treeId, i)
261 if getIsSplitShapeSplit(child) then
262 setWorldRotation(child, getRotation(child))
263 setWorldTranslation(child, getTranslation(child))
264 end
265 end
266
267 addToPhysics(treeId)
268 end
269
270 local updateRange = 2
271 g_densityMapHeightManager:setCollisionMapAreaDirty(x-updateRange, z-updateRange, x+updateRange, z+updateRange, true)
272 g_currentMission.aiSystem:setAreaDirty(x-updateRange, x+updateRange, z-updateRange, z+updateRange)
273 return treeId, splitShapeFileId
274end

loadTreeTrunk

Description
Definition
loadTreeTrunk()
Code
278function TreePlantManager:loadTreeTrunk(treeTypeDesc, x, y, z, dirX, dirY, dirZ, length, growthState, delimb)
279 local treeId, splitShapeFileId = g_treePlantManager:loadTreeNode(treeTypeDesc, x, y, z, 0,0,0, growthState)
280
281 if treeId ~= 0 then
282 if getFileIdHasSplitShapes(splitShapeFileId) then
283 local tree = {}
284 tree.node = treeId
285 tree.growthState = growthState
286 tree.x, tree.y, tree.z = x,y,z
287 tree.rx, tree.ry, tree.rz = 0, 0, 0
288 tree.treeType = treeTypeDesc.index
289 tree.splitShapeFileId = splitShapeFileId
290 tree.hasSplitShapes = getFileIdHasSplitShapes(splitShapeFileId)
291 table.insert(self.treesData.splitTrees, tree)
292
293 self.loadTreeTrunkData = {framesLeft=2, shape=treeId+2, x=x, y=y, z=z, length=length, offset=0.5, dirX=dirX, dirY=dirY, dirZ=dirZ, delimb=delimb}
294 else
295 delete(treeId)
296 end
297 end
298end

loadTreeTypes

Description
Definition
loadTreeTypes()
Code
97function TreePlantManager:loadTreeTypes(xmlFile, missionInfo, baseDirectory, isBaseType)
98 local i = 0
99 while true do
100 local key = string.format("map.treeTypes.treeType(%d)", i)
101 if not hasXMLProperty(xmlFile, key) then
102 break
103 end
104
105 local name = getXMLString(xmlFile, key .. "#name")
106 local nameI18N = getXMLString(xmlFile, key .. "#nameI18N")
107 local growthTimeHours = getXMLFloat(xmlFile, key .. "#growthTimeHours")
108
109 if name == nil or nameI18N == nil or growthTimeHours == nil then
110 print("Warning: A treetype needs valid values for 'name', 'nameI18N', 'growthTimeHours'. Problem found at '"..tostring(key).."'")
111 end
112
113 local filenames = {}
114 local j = 0
115 while true do
116 local stageKey = string.format("%s.stage(%d)", key, j)
117 if not hasXMLProperty(xmlFile, stageKey) then
118 break
119 end
120 local filename = getXMLString(xmlFile, stageKey .. "#filename")
121 if filename ~= nil then
122 local path = Utils.getFilename(filename, baseDirectory)
123 table.insert(filenames, path)
124 end
125 j = j + 1
126 end
127 if #filenames == 0 then
128 print("Warning: A treetype needs valid 'stage#filename' entries. '"..tostring(key).."'")
129 end
130
131 self:registerTreeType(name, nameI18N, filenames, growthTimeHours, isBaseType)
132
133 i = i + 1
134 end
135
136 return true
137end

new

Description
Definition
new()
Code
20function TreePlantManager.new(customMt)
21 local self = AbstractManager.new(customMt or TreePlantManager_mt)
22 return self
23end

plantTree

Description
Definition
plantTree()
Code
186function TreePlantManager:plantTree(treeType, x,y,z, rx,ry,rz, growthState, growthStateI, isGrowing, splitShapeFileId)
187 local treesData = self.treesData
188 local treeTypeDesc = self.indexToTreeType[treeType]
189 if treeTypeDesc ~= nil then
190 growthState = MathUtil.clamp(growthState, 0, 1)
191 if growthStateI == nil then
192 growthStateI = math.floor(growthState*(table.getn(treeTypeDesc.treeFilenames)-1))+1
193 end
194 local treeId, splitShapeFileId = self:loadTreeNode(treeTypeDesc, x,y,z, rx,ry,rz, growthStateI, splitShapeFileId)
195
196 local tree = {}
197 tree.node = treeId
198 isGrowing = Utils.getNoNil(isGrowing, true)
199 if table.getn(treeTypeDesc.treeFilenames) <= 1 then
200 tree.growthState = 1
201 isGrowing = false
202 else
203 tree.growthState = growthState
204 end
205 tree.x, tree.y, tree.z = x,y,z
206 tree.rx, tree.ry, tree.rz = rx,ry,rz
207 tree.treeType = treeType
208 tree.splitShapeFileId = splitShapeFileId
209 tree.hasSplitShapes = getFileIdHasSplitShapes(splitShapeFileId)
210 if isGrowing then
211 tree.origSplitShape = getChildAt(treeId, 0)
212 table.insert(treesData.growingTrees, tree)
213 else
214 table.insert(treesData.splitTrees, tree)
215 end
216 if not tree.hasSplitShapes then
217 self.numTreesWithoutSplits = self.numTreesWithoutSplits + 1
218 treesData.numTreesWithoutSplits = treesData.numTreesWithoutSplits + 1
219 end
220
221 g_server:broadcastEvent(TreePlantEvent.new(treeType, x,y,z, rx,ry,rz, growthState, splitShapeFileId, isGrowing))
222
223 return treeId
224 end
225end

readFromServerStream

Description
Definition
readFromServerStream()
Code
637function TreePlantManager:readFromServerStream(streamId)
638 local treesData = self.treesData
639
640 local numTrees = streamReadInt32(streamId)
641 for i=1, numTrees do
642 local treeType = streamReadInt32(streamId)
643 local x = streamReadFloat32(streamId)
644 local y = streamReadFloat32(streamId)
645 local z = streamReadFloat32(streamId)
646 local rx = streamReadFloat32(streamId)
647 local ry = streamReadFloat32(streamId)
648 local rz = streamReadFloat32(streamId)
649 local growthStateI = streamReadInt8(streamId)
650 local serverSplitShapeFileId = streamReadInt32(streamId)
651
652 local treeTypeDesc = self.indexToTreeType[treeType]
653 if treeTypeDesc ~= nil then
654 local nodeId, splitShapeFileId = self:loadTreeNode(treeTypeDesc, x,y,z, rx,ry,rz, growthStateI, -1)
655 setSplitShapesFileIdMapping(splitShapeFileId, serverSplitShapeFileId)
656 treesData.clientTrees[serverSplitShapeFileId] = nodeId
657 end
658 end
659end

registerTreeType

Description
Definition
registerTreeType()
Code
141function TreePlantManager:registerTreeType(name, nameI18N, treeFilenames, growthTimeHours, isBaseType)
142 name = string.upper(name)
143
144 if isBaseType and self.nameToTreeType[name] ~= nil then
145 print("Warning: TreeType '"..tostring(name).."' already exists. Ignoring treeType!")
146 return nil
147 end
148
149 local treeType = self.nameToTreeType[name]
150 if treeType == nil then
151 treeType = {}
152 treeType.name = name
153 treeType.nameI18N = nameI18N
154 treeType.index = #self.treeTypes + 1
155 table.insert(self.treeTypes, treeType)
156 self.indexToTreeType[treeType.index] = treeType
157 self.nameToTreeType[name] = treeType
158 end
159
160 treeType.treeFilenames = treeFilenames
161 treeType.growthTimeHours = growthTimeHours
162
163 return treeType
164end

removeClientTree

Description
Definition
removeClientTree()
Code
728function TreePlantManager:removeClientTree(serverSplitShapeFileId)
729 if self.treesData ~= nil then
730 self.treesData.clientTrees[serverSplitShapeFileId] = nil
731 end
732end

removingSplitShape

Description
Remove any known state about a split shape
Definition
removingSplitShape()
Code
780function TreePlantManager:removingSplitShape(shape)
781 -- At this point the shape does not exist anymore!
782 self.activeDecayingSplitShapes[shape] = nil
783end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
580function TreePlantManager:saveToXMLFile(xmlFilename)
581 ---- save mappings to xml
582 local xmlFile = createXMLFile("treePlantXML", xmlFilename, "treePlant")
583 if xmlFile ~= nil then
584 self:cleanupDeletedTrees()
585
586 local index = 0
587 for _, tree in pairs(self.treesData.growingTrees) do
588 local treeTypeDesc = self:getTreeTypeDescFromIndex(tree.treeType)
589 local treeTypeName = treeTypeDesc.name
590 local isGrowing = (getChildAt(tree.node, 0) == tree.origSplitShape)
591 local growthStateI = math.floor( tree.growthState * (table.getn(treeTypeDesc.treeFilenames) - 1) ) + 1
592 local splitShapeFileId = Utils.getNoNil(tree.splitShapeFileId, -1)
593
594 local treeKey = string.format("treePlant.tree(%d)", index)
595 setXMLString(xmlFile, treeKey.."#treeType", treeTypeName)
596 setXMLString(xmlFile, treeKey.."#position", string.format("%.4f %.4f %.4f", tree.x, tree.y, tree.z))
597 setXMLString(xmlFile, treeKey.."#rotation", string.format("%.4f %.4f %.4f", math.deg(tree.rx), math.deg(tree.ry), math.deg(tree.rz)))
598 setXMLFloat(xmlFile, treeKey.."#growthState", tree.growthState)
599 setXMLInt(xmlFile, treeKey.."#growthStateI", growthStateI)
600 setXMLBool(xmlFile, treeKey.."#isGrowing", isGrowing)
601 setXMLInt(xmlFile, treeKey.."#splitShapeFileId", splitShapeFileId)
602
603 index = index + 1
604 end
605
606 for _, tree in pairs(self.treesData.splitTrees) do
607 local treeTypeDesc = self:getTreeTypeDescFromIndex(tree.treeType)
608 local treeTypeName = treeTypeDesc.name
609 local isGrowing = false
610 local growthStateI = math.floor( tree.growthState * (table.getn(treeTypeDesc.treeFilenames) - 1) ) + 1
611 local splitShapeFileId = Utils.getNoNil(tree.splitShapeFileId, -1)
612
613 -- Note: we also save growthStateI so that we don't have issues with precision and load a different i3d when loading the savegame
614 local treeKey = string.format("treePlant.tree(%d)", index)
615 setXMLString(xmlFile, treeKey.."#treeType", treeTypeName)
616 setXMLString(xmlFile, treeKey.."#position", string.format("%.4f %.4f %.4f", tree.x, tree.y, tree.z))
617 setXMLString(xmlFile, treeKey.."#rotation", string.format("%.4f %.4f %.4f", math.deg(tree.rx), math.deg(tree.ry), math.deg(tree.rz)))
618 setXMLFloat(xmlFile, treeKey.."#growthState", tree.growthState)
619 setXMLInt(xmlFile, treeKey.."#growthStateI", growthStateI)
620 setXMLBool(xmlFile, treeKey.."#isGrowing", isGrowing)
621 setXMLInt(xmlFile, treeKey.."#splitShapeFileId", splitShapeFileId)
622
623 index = index + 1
624 end
625
626 saveXMLFile(xmlFile)
627 delete(xmlFile)
628
629 return true
630 end
631
632 return false
633end

setSplitShapeLeafScaleAndVariation

Description
Definition
setSplitShapeLeafScaleAndVariation()
Code
787function TreePlantManager:setSplitShapeLeafScaleAndVariation(shape, scale, variation)
788 -- Splitshape is a trunk, and possibly has attachments. (Engine removes attachments when needed)
789 I3DUtil.setShaderParameterRec(shape, "windSnowLeafScale", 0, 0, scale, variation)
790end

unloadMapData

Description
Definition
unloadMapData()
Code
85function TreePlantManager:unloadMapData()
86 for i3dFilename, requestId in pairs(self.treeFileCache) do
87 g_i3DManager:releaseSharedI3DFile(requestId)
88 self.treeFileCache[i3dFilename] = true
89 end
90
91 self:deleteTreesData()
92 TreePlantManager:superClass().unloadMapData(self)
93end

updateTrees

Description
Definition
updateTrees()
Code
309function TreePlantManager:updateTrees(dt, dtGame)
310 local treesData = self.treesData
311 treesData.updateDtGame = treesData.updateDtGame + dtGame
312
313 -- update all 60 ingame minutes
314 if treesData.updateDtGame > 1000*60*60 then
315 self:cleanupDeletedTrees()
316
317 local time = treesData.updateDtGame
318 local dtHours = time / (1000*60*60) * g_currentMission.environment.timeAdjustment
319 treesData.updateDtGame = 0
320 local numGrowingTrees = #treesData.growingTrees
321
322 local i = 1
323 while i <= numGrowingTrees do
324 local tree = treesData.growingTrees[i]
325
326 -- Check if the tree has been cut in the mean time
327 if getChildAt(tree.node, 0) ~= tree.origSplitShape then
328 -- The tree has been cut, it will not grow anymore
329 table.remove(treesData.growingTrees, i)
330 numGrowingTrees = numGrowingTrees - 1
331 tree.origSplitShape = nil
332 table.insert(treesData.splitTrees, tree)
333 else
334 local treeTypeDesc = self.indexToTreeType[tree.treeType]
335 local numTreeFiles = table.getn(treeTypeDesc.treeFilenames)
336 local growthState = tree.growthState
337 -- TODO check for collisions
338 local oldGrowthStateI = math.floor(growthState * (numTreeFiles - 1)) + 1
339 growthState = math.min(growthState + dtHours / treeTypeDesc.growthTimeHours, 1)
340 local growthStateI = math.floor(growthState * (numTreeFiles - 1)) + 1
341
342 tree.growthState = growthState
343 if oldGrowthStateI ~= growthStateI and treeTypeDesc.treeFilenames[oldGrowthStateI] ~= treeTypeDesc.treeFilenames[growthStateI] then
344
345 -- Delete the old tree
346 delete(tree.node)
347
348 if not tree.hasSplitShapes then
349 self.numTreesWithoutSplits = math.max(self.numTreesWithoutSplits - 1, 0)
350 treesData.numTreesWithoutSplits = math.max(treesData.numTreesWithoutSplits - 1, 0)
351 end
352
353 -- Create the new tree
354 local treeId, splitShapeFileId = self:loadTreeNode(treeTypeDesc, tree.x, tree.y, tree.z, tree.rx, tree.ry, tree.rz, growthStateI, -1)
355
356 g_server:broadcastEvent(TreeGrowEvent.new(tree.treeType, tree.x, tree.y, tree.z, tree.rx, tree.ry, tree.rz, tree.growthState, splitShapeFileId, tree.splitShapeFileId))
357
358 tree.origSplitShape = getChildAt(treeId, 0)
359 tree.splitShapeFileId = splitShapeFileId
360 tree.hasSplitShapes = getFileIdHasSplitShapes(splitShapeFileId)
361 tree.node = treeId
362
363 -- update collision map
364 local range = 2.5
365 local x, _, z = getWorldTranslation(treeId)
366 g_densityMapHeightManager:setCollisionMapAreaDirty(x-range, z-range, x+range, z+range, true)
367 g_currentMission.aiSystem:setAreaDirty(x-range, x+range, z-range, z+range)
368
369 if not tree.hasSplitShapes then
370 self.numTreesWithoutSplits = self.numTreesWithoutSplits + 1
371 treesData.numTreesWithoutSplits = treesData.numTreesWithoutSplits + 1
372 end
373 end
374
375 if growthStateI >= numTreeFiles then
376 -- Reached max grow level, can't grow anymore
377 table.remove(treesData.growingTrees, i)
378 numGrowingTrees = numGrowingTrees-1
379 tree.origSplitShape = nil
380 table.insert(treesData.splitTrees, tree)
381 else
382 i = i+1
383 end
384 end
385 end
386 end
387
388 local curTime = g_currentMission.time
389 for joint in pairs(treesData.treeCutJoints) do
390 if joint.destroyTime <= curTime or not entityExists(joint.shape) then
391 removeJoint(joint.jointIndex)
392 treesData.treeCutJoints[joint] = nil
393 else
394 local x1,y1,z1 = localDirectionToWorld(joint.shape, joint.lnx, joint.lny, joint.lnz)
395 if x1*joint.nx + y1*joint.ny + z1*joint.nz < joint.maxCosAngle then
396 removeJoint(joint.jointIndex)
397 treesData.treeCutJoints[joint] = nil
398 end
399 end
400 end
401
402 if self.loadTreeTrunkData ~= nil then
403 self.loadTreeTrunkData.framesLeft = self.loadTreeTrunkData.framesLeft - 1
404 -- first cut and remove upper part of tree
405 if self.loadTreeTrunkData.framesLeft == 1 then
406 local nx,ny,nz = 0, 1, 0
407 local yx,yy,yz = -1, 0, 0
408 local x,y,z = self.loadTreeTrunkData.x+1, self.loadTreeTrunkData.y, self.loadTreeTrunkData.z-1
409
410 self.loadTreeTrunkData.parts = {}
411
412 local shape = self.loadTreeTrunkData.shape
413 if shape ~= nil and shape ~= 0 then
414 self.shapeBeingCut = shape
415 splitShape(shape, x,y+self.loadTreeTrunkData.length+self.loadTreeTrunkData.offset,z, nx,ny,nz, yx,yy,yz, 4, 4, "cutTreeTrunkCallback", self)
416 self:removingSplitShape(shape)
417 for _, p in pairs(self.loadTreeTrunkData.parts) do
418 if p.isAbove then
419 delete(p.shape)
420 else
421 self.loadTreeTrunkData.shape = p.shape
422 end
423 end
424 end
425
426 -- second cut lower part to get final length
427 elseif self.loadTreeTrunkData.framesLeft == 0 then
428 local nx,ny,nz = 0, 1, 0
429 local yx,yy,yz = -1, 0, 0
430 local x,y,z = self.loadTreeTrunkData.x+1, self.loadTreeTrunkData.y, self.loadTreeTrunkData.z-1
431
432 self.loadTreeTrunkData.parts = {}
433 local shape = self.loadTreeTrunkData.shape
434 if shape ~= nil and shape ~= 0 then
435 splitShape(shape, x,y+self.loadTreeTrunkData.offset,z, nx,ny,nz, yx,yy,yz, 4, 4, "cutTreeTrunkCallback", self)
436 local finalShape = nil
437 for _, p in pairs(self.loadTreeTrunkData.parts) do
438 if p.isBelow then
439 delete(p.shape)
440 else
441 finalShape = p.shape
442 end
443 end
444 -- set correct rotation of final chunk
445 if finalShape ~= nil then
446 if self.loadTreeTrunkData.delimb then
447 removeSplitShapeAttachments(finalShape, x,y+self.loadTreeTrunkData.offset,z, nx,ny,nz, yx,yy,yz, self.loadTreeTrunkData.length, 4, 4)
448 end
449
450 removeFromPhysics(finalShape)
451 setDirection(finalShape, 0, -1, 0, self.loadTreeTrunkData.dirX, self.loadTreeTrunkData.dirY, self.loadTreeTrunkData.dirZ)
452 addToPhysics(finalShape)
453 else
454 Logging.error("Unable to cut tree trunk with length '%s'. Try using a different value", self.loadTreeTrunkData.length)
455 end
456 end
457
458 self.loadTreeTrunkData = nil
459 end
460 end
461
462 self.updateDecayDtGame = self.updateDecayDtGame + dtGame
463 if self.updateDecayDtGame > TreePlantManager.DECAY_INTERVAL then
464 -- Update seasonal state of active split shapes
465 for shape, data in pairs(self.activeDecayingSplitShapes) do
466 if not entityExists(shape) then
467 self.activeDecayingSplitShapes[shape] = nil
468 elseif data.state > 0 then
469 local newState = math.max(data.state - TreePlantManager.DECAY_DURATION_INV * self.updateDecayDtGame, 0)
470
471 self:setSplitShapeLeafScaleAndVariation(shape, newState, data.variation)
472 self.activeDecayingSplitShapes[shape].state = newState
473 end
474 end
475
476 self.updateDecayDtGame = 0
477 end
478end

writeToClientStream

Description
Definition
writeToClientStream()
Code
663function TreePlantManager:writeToClientStream(streamId)
664 local treesData = self.treesData
665
666 self:cleanupDeletedTrees()
667
668 local numTrees = #treesData.growingTrees + #treesData.splitTrees
669
670 streamWriteInt32(streamId, numTrees)
671 for _, tree in pairs(treesData.growingTrees) do
672 streamWriteInt32(streamId, tree.treeType)
673 streamWriteFloat32(streamId, tree.x)
674 streamWriteFloat32(streamId, tree.y)
675 streamWriteFloat32(streamId, tree.z)
676 streamWriteFloat32(streamId, tree.rx)
677 streamWriteFloat32(streamId, tree.ry)
678 streamWriteFloat32(streamId, tree.rz)
679 local treeTypeDesc = self.indexToTreeType[tree.treeType]
680 local growthStateI = math.floor(tree.growthState*(table.getn(treeTypeDesc.treeFilenames)-1))+1
681 streamWriteInt8(streamId, growthStateI)
682 streamWriteInt32(streamId, tree.splitShapeFileId)
683 end
684 for _, tree in pairs(treesData.splitTrees) do
685 streamWriteInt32(streamId, tree.treeType)
686 streamWriteFloat32(streamId, tree.x)
687 streamWriteFloat32(streamId, tree.y)
688 streamWriteFloat32(streamId, tree.z)
689 streamWriteFloat32(streamId, tree.rx)
690 streamWriteFloat32(streamId, tree.ry)
691 streamWriteFloat32(streamId, tree.rz)
692 local treeTypeDesc = self.indexToTreeType[tree.treeType]
693 local growthStateI = math.floor(tree.growthState*(table.getn(treeTypeDesc.treeFilenames)-1))+1
694 streamWriteInt8(streamId, growthStateI)
695 streamWriteInt32(streamId, tree.splitShapeFileId)
696 end
697end