Sprache Deutsch Language English

Script Dokumentation LS 2015 - TreePlantUtil (Patch 1.3)

Script Dokumentation Übersicht

scripts/TreePlantUtil.lua

Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
1-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
2
3TreePlantUtil = {};
4
5TreePlantUtil.TREETYPE_UNKNOWN = 0;
6TreePlantUtil.NUM_TREETYPES = 0;
7
8TreePlantUtil.treeTypes = {};
9TreePlantUtil.treeTypeIndexToDesc = {};
10
11function TreePlantUtil.registerTreeType(name, nameI18N, treeFilenames, growthTimeHours)
12 local key = "TREETYPE_"..string.upper(name);
13 if TreePlantUtil[key] == nil then
14 TreePlantUtil.NUM_TREETYPES = TreePlantUtil.NUM_TREETYPES + 1;
15 TreePlantUtil[key] = TreePlantUtil.NUM_TREETYPES;
16
17 local desc = {name = name, nameI18N=nameI18N, index = TreePlantUtil.NUM_TREETYPES};
18 desc.treeFilenames = treeFilenames;
19 desc.growthTimeHours = growthTimeHours;
20 TreePlantUtil.treeTypes[name] = desc;
21 TreePlantUtil.treeTypeIndexToDesc[TreePlantUtil.NUM_TREETYPES] = desc;
22 end
23end
24
25function TreePlantUtil.initTreesData(treesData)
26 local rootNode = createTransformGroup("trees");
27 link(getRootNode(), rootNode);
28 treesData.rootNode = rootNode;
29 treesData.growingTrees = {};
30 treesData.splitTrees = {};
31 treesData.clientTrees = {};
32 treesData.updateDtGame = 0;
33 treesData.treeCutJoints = {};
34end
35
36function TreePlantUtil.deleteTreesData(treesData)
37 delete(treesData.rootNode);
38end
39
40function TreePlantUtil.plantTree(treesData, treeType, x,y,z, rx,ry,rz, growthState, growthStateI, isGrowing, splitShapeFileId)
41 local treeTypeDesc = TreePlantUtil.treeTypeIndexToDesc[treeType];
42 if treeTypeDesc ~= nil then
43 growthState = Utils.clamp(growthState, 0, 1);
44 if growthStateI == nil then
45 growthStateI = math.floor(growthState*(table.getn(treeTypeDesc.treeFilenames)-1))+1;
46 end
47 local treeId, splitShapeFileId = TreePlantUtil.loadTreeNode(treesData, treeTypeDesc, x,y,z, rx,ry,rz, growthStateI, splitShapeFileId)
48
49 local tree = {};
50 tree.node = treeId;
51 local isGrowing = Utils.getNoNil(isGrowing, true);
52 if table.getn(treeTypeDesc.treeFilenames) <= 1 then
53 tree.growthState = 1;
54 isGrowing = false;
55 else
56 tree.growthState = growthState;
57 end
58 tree.x, tree.y, tree.z = x,y,z;
59 tree.rx, tree.ry, tree.rz = rx,ry,rz;
60 tree.treeType = treeType;
61 tree.splitShapeFileId = splitShapeFileId;
62 if isGrowing then
63 tree.origSplitShape = getChildAt(treeId, 0);
64 table.insert(treesData.growingTrees, tree);
65 else
66 table.insert(treesData.splitTrees, tree);
67 end
68 g_server:broadcastEvent(TreePlantEvent:new(treeType, x,y,z, rx,ry,rz, growthState, splitShapeFileId));
69 end
70end
71
72function TreePlantUtil.loadTreeNode(treesData, treeTypeDesc, x,y,z, rx,ry,rz, growthStateI, splitShapeFileId)
73 growthStateI = math.min(growthStateI, table.getn(treeTypeDesc.treeFilenames));
74 local i3dFilename = treeTypeDesc.treeFilenames[growthStateI];
75
76 -- make sure the i3d is loaded, so that the file id will not be used by the i3d clone source
77 setSplitShapesLoadingFileId(-1);
78 setSplitShapesNextFileId(true);
79 Utils.fillSharedI3DFileCache(i3dFilename, nil);
80
81 setSplitShapesLoadingFileId(Utils.getNoNil(splitShapeFileId, -1));
82 local splitShapeFileId = setSplitShapesNextFileId();
83
84 local treeId = Utils.loadSharedI3DFile(i3dFilename, nil, false, false);
85 link(treesData.rootNode, treeId);
86
87 setTranslation(treeId, x,y,z);
88 setRotation(treeId, rx,ry,rz);
89 addToPhysics(treeId);
90
91 return treeId, splitShapeFileId;
92end
93
94function TreePlantUtil.updateTrees(treesData, dt, dtGame)
95 treesData.updateDtGame = treesData.updateDtGame + dtGame;
96
97 -- update all 10 ingame minutes
98 if treesData.updateDtGame > 1000*60*10 then
99 local dtHours = treesData.updateDtGame / (1000*60*60);
100 treesData.updateDtGame = 0;
101 local numGrowingTrees = #treesData.growingTrees;
102 local i = 1;
103 while i<=numGrowingTrees do
104 local tree = treesData.growingTrees[i];
105 -- Check if the tree has been cut in the mean time
106 if getNumOfChildren(tree.node) == 0 then
107 -- The tree has been removed completely, remove from list
108 table.remove(treesData.growingTrees, i);
109 numGrowingTrees = numGrowingTrees-1;
110 delete(tree.node);
111 elseif getChildAt(tree.node, 0) ~= tree.origSplitShape then
112 -- The tree has been cut, it will not grow anymore
113 table.remove(treesData.growingTrees, i);
114 numGrowingTrees = numGrowingTrees-1;
115 tree.origSplitShape = nil;
116 table.insert(treesData.splitTrees, tree);
117 else
118 local treeTypeDesc = TreePlantUtil.treeTypeIndexToDesc[tree.treeType];
119 local numTreeFiles = table.getn(treeTypeDesc.treeFilenames);
120 local growthState = tree.growthState;
121 -- TODO check for collisions
122 local oldGrowthStateI = math.floor(growthState*(numTreeFiles-1))+1;
123 growthState = math.min(growthState+dtHours/treeTypeDesc.growthTimeHours, 1);
124 local growthStateI = math.floor(growthState*(numTreeFiles-1))+1;
125
126 tree.growthState = growthState;
127 if oldGrowthStateI ~= growthStateI and treeTypeDesc.treeFilenames[oldGrowthStateI] ~= treeTypeDesc.treeFilenames[growthStateI] then
128 local i3dFilename = treeTypeDesc.treeFilenames[growthStateI];
129
130 -- make sure the i3d is loaded, so that the file id will not be used by the i3d clone source
131 setSplitShapesLoadingFileId(-1);
132 setSplitShapesNextFileId(true);
133 Utils.fillSharedI3DFileCache(i3dFilename, nil);
134
135 setSplitShapesLoadingFileId(-1); -- growing always creates a fresh/unsaved tree
136 local splitShapeFileId = setSplitShapesNextFileId();
137
138 local treeId = Utils.loadSharedI3DFile(i3dFilename, nil, false, false);
139 link(treesData.rootNode, treeId);
140 setTranslation(treeId, tree.x, tree.y, tree.z);
141 setRotation(treeId, tree.rx, tree.ry, tree.rz);
142 delete(tree.node);
143
144 addToPhysics(treeId);
145 local oldSplitShapeFileId = tree.splitShapeFileId;
146
147 tree.origSplitShape = getChildAt(treeId, 0);
148 tree.splitShapeFileId = splitShapeFileId;
149 tree.node = treeId;
150
151 g_server:broadcastEvent(TreeGrowEvent:new(tree.treeType, tree.x, tree.y, tree.z, tree.rx, tree.ry, tree.rz, tree.growthState, splitShapeFileId, oldSplitShapeFileId));
152 end
153 if growthStateI >= numTreeFiles then
154 -- Reached max grow level, can't grow anymore
155 table.remove(treesData.growingTrees, i);
156 numGrowingTrees = numGrowingTrees-1;
157 tree.origSplitShape = nil;
158 table.insert(treesData.splitTrees, tree);
159 else
160 i = i+1;
161 end
162 end
163 end
164 end
165
166 local curTime = g_currentMission.time;
167 for joint in pairs(treesData.treeCutJoints) do
168 if joint.destroyTime <= curTime or not entityExists(joint.shape) then
169 removeJoint(joint.jointIndex);
170 treesData.treeCutJoints[joint] = nil;
171 else
172 local x1,y1,z1 = localDirectionToWorld(joint.shape, joint.lnx, joint.lny, joint.lnz);
173 if x1*joint.nx + y1*joint.ny + z1*joint.nz < joint.maxCosAngle then
174 removeJoint(joint.jointIndex);
175 treesData.treeCutJoints[joint] = nil;
176 end
177 end
178 end
179end
180
181function TreePlantUtil.addTreeCutJoint(treesData, jointIndex, shape, nx,ny,nz, maxAngle, maxLifetime)
182 local lnx,lny,lnz = worldDirectionToLocal(shape, nx,ny,nz);
183 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};
184 treesData.treeCutJoints[joint] = joint;
185end
186
187function TreePlantUtil.loadFromAttributesAndNodes(treesData, xmlFile, baseKey)
188
189 local i=0;
190 while true do
191 local key = string.format("%s.tree(%d)", baseKey, i);
192 if not hasXMLProperty(xmlFile, key) then
193 break
194 end
195
196 local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, key.."#position"));
197 local rx,ry,rz = Utils.getVectorFromString(getXMLString(xmlFile, key.."#rotation"));
198
199 local treeTypeName = getXMLString(xmlFile, key.."#treeType");
200 local treeType;
201 if treeTypeName ~= nil then
202 treeType = TreePlantUtil.treeTypes[treeTypeName];
203 end
204 if x ~= nil and y ~= nil and z ~= nil and rx ~= nil and ry ~= nil and rz ~= nil and treeType ~= nil then
205 local growthState = Utils.getNoNil(getXMLFloat(xmlFile, key.."#growthState"), 0.0);
206 local isGrowing = Utils.getNoNil(getXMLBool(xmlFile, key.."#isGrowing"), true);
207 local growthStateI = getXMLInt(xmlFile, key.."#growthStateI"); -- note: might be nil, plantTree will use default behaviour (calculate from float growthState)
208 local splitShapeFileId = getXMLInt(xmlFile, key.."#splitShapeFileId"); -- note: might be nil if not available
209 TreePlantUtil.plantTree(treesData, treeType.index, x,y,z, rx,ry,rz, growthState, growthStateI, isGrowing, splitShapeFileId);
210 end
211
212 i=i+1;
213 end
214end
215
216function TreePlantUtil.getSaveAttributesAndNodes(treesData, nodeIdent)
217 local attributes = '';
218 local nodes = "";
219
220 local firstTreeWritten = false;
221 for _, tree in pairs(treesData.growingTrees) do
222 -- only save trees which have not been removed in the meantime
223 if getNumOfChildren(tree.node) > 0 then
224 local isGrowing = (getChildAt(tree.node, 0) == tree.origSplitShape);
225 nodes = nodes .. TreePlantUtil.getTreeSaveAttributesAndNodes(treesData, nodeIdent, tree, isGrowing, firstTreeWritten);
226 firstTreeWritten = true;
227 end
228 end
229 for _, tree in pairs(treesData.splitTrees) do
230 -- only save trees which have not been removed in the meantime
231 if getNumOfChildren(tree.node) > 0 then
232 nodes = nodes .. TreePlantUtil.getTreeSaveAttributesAndNodes(treesData, nodeIdent, tree, false, firstTreeWritten);
233 firstTreeWritten = true;
234 end
235 end
236 return attributes,nodes;
237end
238
239function TreePlantUtil.getTreeSaveAttributesAndNodes(treesData, nodeIdent, tree, isGrowing, firstTreeWritten)
240 local treeTypeDesc = TreePlantUtil.treeTypeIndexToDesc[tree.treeType];
241 local treeTypeName = treeTypeDesc.name;
242 local growthStateI = math.floor(tree.growthState*(table.getn(treeTypeDesc.treeFilenames)-1))+1;
243
244 if firstTreeWritten then
245 nodeIdent = "\n"..nodeIdent;
246 end
247
248 local splitShapeFileId = Utils.getNoNil(tree.splitShapeFileId, -1);
249
250 -- Note: we also save growthStateI so that we don't have issues with precision and load a different i3d when loading the savegame
251 return string.format('%s<tree treeType="%s" position="%.4f %.4f %.4f" rotation="%.4f %.4f %.4f" growthState="%.4f" growthStateI="%d" isGrowing="%s" splitShapeFileId="%d"/>',
252 nodeIdent, treeTypeName, tree.x,tree.y,tree.z, tree.rx,tree.ry,tree.rz, tree.growthState,growthStateI, tostring(isGrowing), splitShapeFileId);
253end
254
255function TreePlantUtil.readFromServerStream(treesData, streamId)
256 local numTrees = streamReadInt32(streamId);
257 for i=1, numTrees do
258 local treeType = streamReadInt32(streamId);
259 local x = streamReadFloat32(streamId);
260 local y = streamReadFloat32(streamId);
261 local z = streamReadFloat32(streamId);
262 local rx = streamReadFloat32(streamId);
263 local ry = streamReadFloat32(streamId);
264 local rz = streamReadFloat32(streamId);
265 local growthStateI = streamReadInt8(streamId);
266 local serverSplitShapeFileId = streamReadInt32(streamId);
267
268 local treeTypeDesc = TreePlantUtil.treeTypeIndexToDesc[treeType];
269 if treeTypeDesc ~= nil then
270 local nodeId, splitShapeFileId = TreePlantUtil.loadTreeNode(treesData, treeTypeDesc, x,y,z, rx,ry,rz, growthStateI, -1);
271 setSplitShapesFileIdMapping(splitShapeFileId, serverSplitShapeFileId);
272 treesData.clientTrees[serverSplitShapeFileId] = nodeId;
273 end
274 end
275end
276
277function TreePlantUtil.writeToClientStream(treesData, streamId)
278 local numTrees = 0;
279 for _, tree in pairs(treesData.growingTrees) do
280 if getNumOfChildren(tree.node) > 0 then
281 numTrees = numTrees+1;
282 end
283 end
284 for _, tree in pairs(treesData.splitTrees) do
285 if getNumOfChildren(tree.node) > 0 then
286 numTrees = numTrees+1;
287 end
288 end
289
290 streamWriteInt32(streamId, numTrees);
291 for _, tree in pairs(treesData.growingTrees) do
292 -- only save trees which have not been removed in the meantime
293 if getNumOfChildren(tree.node) > 0 then
294 streamWriteInt32(streamId, tree.treeType);
295 streamWriteFloat32(streamId, tree.x);
296 streamWriteFloat32(streamId, tree.y);
297 streamWriteFloat32(streamId, tree.z);
298 streamWriteFloat32(streamId, tree.rx);
299 streamWriteFloat32(streamId, tree.ry);
300 streamWriteFloat32(streamId, tree.rz);
301 local treeTypeDesc = TreePlantUtil.treeTypeIndexToDesc[tree.treeType];
302 local growthStateI = math.floor(tree.growthState*(table.getn(treeTypeDesc.treeFilenames)-1))+1;
303 streamWriteInt8(streamId, growthStateI);
304 streamWriteInt32(streamId, tree.splitShapeFileId);
305 end
306 end
307 for _, tree in pairs(treesData.splitTrees) do
308 -- only save trees which have not been removed in the meantime
309 if getNumOfChildren(tree.node) > 0 then
310 streamWriteInt32(streamId, tree.treeType);
311 streamWriteFloat32(streamId, tree.x);
312 streamWriteFloat32(streamId, tree.y);
313 streamWriteFloat32(streamId, tree.z);
314 streamWriteFloat32(streamId, tree.rx);
315 streamWriteFloat32(streamId, tree.ry);
316 streamWriteFloat32(streamId, tree.rz);
317 local treeTypeDesc = TreePlantUtil.treeTypeIndexToDesc[tree.treeType];
318 local growthStateI = math.floor(tree.growthState*(table.getn(treeTypeDesc.treeFilenames)-1))+1;
319 streamWriteInt8(streamId, growthStateI);
320 streamWriteInt32(streamId, tree.splitShapeFileId);
321 end
322 end
323end
Copyright (c) 2008-2015 GIANTS Software GmbH, Confidential, All Rights Reserved.
This document is to be published solely by ls-mods.de
Script Dokumentation Übersicht