24 | function WorkParticles:preLoad(savegame) |
25 | self.getDoGroundManipulation = WorkParticles.getDoGroundManipulation; |
26 | self.loadGroundReferenceNodeFromXML = Utils.overwrittenFunction(self.loadGroundReferenceNodeFromXML, WorkParticles.loadGroundReferenceNodeFromXML); |
27 | self.loadGroundParticles = Utils.overwrittenFunction(self.loadGroundParticles, WorkParticles.loadGroundParticles); |
28 | self.loadGroundParticleMapping = Utils.overwrittenFunction(self.loadGroundParticleMapping, WorkParticles.loadGroundParticleMapping); |
29 | self.loadGroundAnimations = Utils.overwrittenFunction(self.loadGroundAnimations, WorkParticles.loadGroundAnimations); |
30 | self.loadGroundAnimationMapping = Utils.overwrittenFunction(self.loadGroundAnimationMapping, WorkParticles.loadGroundAnimationMapping); |
31 | end; |
36 | function WorkParticles:load(savegame) |
37 | |
38 | if self.isClient then |
39 | if hasXMLProperty(self.xmlFile, "vehicle.groundParticleSystem") then |
40 | print("Warning: vehicle.groundParticleSystem is not supported anymore in "..self.configFileName..". Use vehicle.groundParticleAnimations.groundParticle instead!"); |
41 | end; |
42 | if hasXMLProperty(self.xmlFile, "vehicle.groundParticleSystems.groundParticleSystem") then |
43 | print("Warning: vehicle.groundParticleSystems.groundParticleSystem is not supported anymore in "..self.configFileName..". Use vehicle.groundParticleAnimations.groundParticle instead!"); |
44 | end; |
45 | |
46 | self.groundParticleAnimations = {}; |
47 | local i = 0; |
48 | while true do |
49 | local key = string.format("vehicle.groundParticleAnimations.groundParticleAnimation(%d)", i); |
50 | if not hasXMLProperty(self.xmlFile, key) then |
51 | break; |
52 | end; |
53 | local animation = {}; |
54 | if self:loadGroundAnimations(self.xmlFile, key, animation, i) then |
55 | table.insert(self.groundParticleAnimations, animation); |
56 | end |
57 | |
58 | i = i + 1 |
59 | end |
60 | |
61 | self.groundParticles = {}; |
62 | local i = 0; |
63 | while true do |
64 | local key = string.format("vehicle.groundParticleAnimations.groundParticle(%d)", i); |
65 | if not hasXMLProperty(self.xmlFile, key) then |
66 | break; |
67 | end |
68 | |
69 | local particle = {}; |
70 | if self:loadGroundParticles(self.xmlFile, key, particle, i) then |
71 | table.insert(self.groundParticles, particle); |
72 | end |
73 | |
74 | i = i + 1; |
75 | end |
76 | end; |
77 | |
78 | self.groundManipulationSpeedThreshold = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.groundManipulationSpeedThreshold#value"), 5); |
79 | end; |
83 | function WorkParticles:delete() |
84 | if self.isClient then |
85 | for _, animation in pairs(self.groundParticleAnimations) do |
86 | if animation.filename ~= nil then |
87 | Utils.releaseSharedI3DFile(animation.filename, self.baseDirectory, true); |
88 | end |
89 | end; |
90 | |
91 | for _, ps in pairs(self.groundParticles) do |
92 | for _, mapping in ipairs(ps.mappings) do |
93 | ParticleUtil.deleteParticleSystem(mapping.particleSystem); |
94 | end; |
95 | end; |
96 | end; |
97 | end; |
111 | function WorkParticles:updateTick(dt) |
112 | if self.isClient then |
113 | if self:getIsActive() then |
114 | for _, animation in pairs(self.groundParticleAnimations) do |
115 | for _, mapping in pairs(animation.mappings) do |
116 | local refNode = mapping.groundRefNode; |
117 | if refNode ~= nil and refNode.depthNode ~= nil then |
118 | local depth = Utils.clamp(refNode.depth / mapping.maxWorkDepth, 0, 1); |
119 | depth = Utils.clamp(math.min(depth, mapping.lastDepth + refNode.movingDirection*(refNode.movedDistance/0.5)), 0 ,1); |
120 | mapping.lastDepth = depth; |
121 | mapping.speed = mapping.speed - refNode.movedDistance*refNode.movingDirection; |
122 | setVisibility(mapping.animNode, depth ~= 0); |
123 | setShaderParameter(mapping.animNode, "VertxoffsetVertexdeformMotionUVscale", -6, depth, mapping.speed, 1.5, false); |
124 | end; |
125 | end; |
126 | end; |
127 | |
128 | for _,ps in pairs(self.groundParticles) do |
129 | local enabled = self:getDoGroundManipulation(); |
130 | for _, mapping in pairs(ps.mappings) do |
131 | local nodeEnabled = enabled; |
132 | if nodeEnabled then |
133 | nodeEnabled = mapping.groundRefNode.isActive; |
134 | end; |
135 | ParticleUtil.setEmittingState(mapping.particleSystem, nodeEnabled); |
136 | end; |
137 | end; |
138 | end; |
139 | end; |
140 | end; |
147 | function WorkParticles:onDeactivate() |
148 | if self.isClient then |
149 | for _,ps in pairs(self.groundParticles) do |
150 | for _, mapping in pairs(ps.mappings) do |
151 | ParticleUtil.setEmittingState(mapping.particleSystem, false); |
152 | end; |
153 | end; |
154 | for _, animation in pairs(self.groundParticleAnimations) do |
155 | for _, mapping in pairs(animation.mappings) do |
156 | setVisibility(mapping.animNode, false); |
157 | end |
158 | end |
159 | end; |
160 | end; |
193 | function WorkParticles:updateGroundReferenceNode(groundReferenceNode, x, y, z, terrainHeight, densityHeight) |
194 | if self.isClient and groundReferenceNode.depthNode ~= nil then |
195 | local newX, newY, newZ = getWorldTranslation(groundReferenceNode.depthNode); |
196 | if groundReferenceNode.lastPosition == nil then |
197 | groundReferenceNode.lastPosition = {newX, newY, newZ}; |
198 | end; |
199 | local dx, dy, dz = worldDirectionToLocal(groundReferenceNode.depthNode, newX-groundReferenceNode.lastPosition[1], newY-groundReferenceNode.lastPosition[2], newZ-groundReferenceNode.lastPosition[3]); |
200 | groundReferenceNode.movingDirection = 0; |
201 | if dz > 0.0001 then |
202 | groundReferenceNode.movingDirection = 1; |
203 | elseif dz < -0.0001 then |
204 | groundReferenceNode.movingDirection = -1; |
205 | end; |
206 | groundReferenceNode.movedDistance = Utils.vector3Length(dx, dy, dz); |
207 | groundReferenceNode.lastPosition = {newX, newY, newZ}; |
208 | local terrainHeightDepthNode = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, newX, newY, newZ); |
209 | groundReferenceNode.depth = newY - terrainHeightDepthNode; |
210 | end; |
211 | end; |
220 | function WorkParticles:loadGroundAnimations(superFunc, xmlFile, key, animation, index) |
221 | if superFunc ~= nil then |
222 | if not superFunc(self, xmlFile, key, animation, index) then |
223 | return false; |
224 | end |
225 | end |
226 | |
227 | local filenameStr = getXMLString(self.xmlFile, key .. "#file"); |
228 | local i3dNode = nil |
229 | if filenameStr ~= nil then |
230 | i3dNode = Utils.loadSharedI3DFile(filenameStr, self.baseDirectory); |
231 | end |
232 | |
233 | local j = 0; |
234 | while true do |
235 | local nodeBaseName = string.format(key .. ".node(%d)", j); |
236 | if not hasXMLProperty(self.xmlFile, nodeBaseName) then |
237 | break; |
238 | end; |
239 | |
240 | local mapping = {}; |
241 | if self:loadGroundAnimationMapping(xmlFile, nodeBaseName, mapping, j, i3dNode) then |
242 | if animation.mappings == nil then |
243 | animation.mappings = {} |
244 | end |
245 | table.insert(animation.mappings, mapping); |
246 | end |
247 | j = j + 1; |
248 | end |
249 | |
250 | if i3dNode ~= nil and i3dNode ~= 0 then |
251 | -- link after loading to make sure all indices are correct |
252 | for _, mapping in pairs(animation.mappings) do |
253 | link(mapping.node, mapping.animNode); |
254 | setVisibility(mapping.animNode, false); |
255 | end; |
256 | |
257 | animation.filename = filenameStr; |
258 | delete(i3dNode) |
259 | end |
260 | |
261 | return true |
262 | end |
271 | function WorkParticles:loadGroundAnimationMapping(superFunc, xmlFile, key, mapping, index) |
272 | if superFunc ~= nil then |
273 | if not superFunc(self, xmlFile, key, mapping, index) then |
274 | return false; |
275 | end |
276 | end |
277 | |
278 | local node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#index")); |
279 | if node == nil then |
280 | print("Warning: Invalid node index '"..getXMLString(self.xmlFile, key.."#index").."' in '"..self.configFileName.."'!"); |
281 | return false; |
282 | end; |
283 | |
284 | local groundRefIndex = getXMLInt(self.xmlFile, key .. "#refNodeIndex"); |
285 | if groundRefIndex == nil or self.groundReferenceNodes[groundRefIndex+1] == nil then |
286 | print("Warning: Invalid refNodeIndex '"..getXMLString(self.xmlFile, key.."#refNodeIndex").."' in '"..self.configFileName.."'!"); |
287 | return false; |
288 | end; |
289 | |
290 | local animNode = nil |
291 | local animMeshIndex = getXMLString(self.xmlFile, key.."#animMeshIndex") |
292 | if animMeshIndex ~= nil and i3dNode ~= nil and i3dNode ~= 0 then |
293 | animNode = Utils.indexToObject(i3dNode, animMeshIndex); |
294 | if animNode == nil then |
295 | print("Warning: Invalid animMesh index '"..getXMLString(self.xmlFile, key.."#animMeshIndex").."' in '"..self.configFileName.."'!"); |
296 | return false; |
297 | end; |
298 | else |
299 | local materialType = getXMLString(self.xmlFile, key.."#materialType") |
300 | local materialId = Utils.getNoNil(getXMLInt(self.xmlFile, key.."#materialId"), 1) |
301 | if materialType == nil then |
302 | print("Warning: Missing materialType ("..key..") in '"..self.configFileName.."'!"); |
303 | return false; |
304 | end |
305 | |
306 | animNode = node |
307 | |
308 | local material = MaterialUtil.getMaterial(FillUtil.FILLTYPE_UNKNOWN, materialType, materialId); |
309 | if material ~= nil then |
310 | setMaterial(node, material, 0) |
311 | else |
312 | print("Warning: Invalid materialType '"..materialType.."' or materialId .. '"..materialId.."' in '"..self.configFileName.."'!"); |
313 | end |
314 | |
315 | setVisibility(animNode, false); |
316 | end |
317 | |
318 | mapping.node = node; |
319 | mapping.animNode = animNode; |
320 | mapping.groundRefNode = self.groundReferenceNodes[groundRefIndex+1]; |
321 | mapping.lastDepth = 0; |
322 | mapping.speed = 0; |
323 | mapping.maxWorkDepth = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#maxDepth"), -0.1); |
324 | |
325 | return true |
326 | end |
335 | function WorkParticles:loadGroundParticles(superFunc, xmlFile, key, particle, index) |
336 | if superFunc ~= nil then |
337 | if not superFunc(self, xmlFile, key, particle, index) then |
338 | return false; |
339 | end |
340 | end |
341 | |
342 | particle.mappings = {} |
343 | |
344 | local filename = getXMLString(self.xmlFile, key .. "#file"); |
345 | local i3dNode = nil |
346 | if filename ~= nil then |
347 | filename = Utils.getFilename(filename, self.baseDirectory) |
348 | i3dNode = loadI3DFile(filename, true, true, false); |
349 | end |
350 | |
351 | local j = 0; |
352 | while true do |
353 | local nodeBaseName = string.format(key .. ".node(%d)", j); |
354 | if not hasXMLProperty(self.xmlFile, nodeBaseName) then |
355 | break; |
356 | end; |
357 | |
358 | local mapping = {}; |
359 | if self:loadGroundParticleMapping(xmlFile, nodeBaseName, mapping, j, i3dNode) then |
360 | table.insert(particle.mappings, mapping); |
361 | end |
362 | j = j + 1; |
363 | end; |
364 | |
365 | |
366 | if i3dNode ~= nil and i3dNode ~= 0 then |
367 | -- link after loading to make sure all indices are correct |
368 | for _, mapping in pairs(particle.mappings) do |
369 | link(mapping.node, mapping.particleNode); |
370 | ParticleUtil.loadParticleSystemFromNode(mapping.particleNode, mapping.particleSystem, false, true); |
371 | end; |
372 | |
373 | particle.filename = filename; |
374 | delete(i3dNode) |
375 | end |
376 | |
377 | return true |
378 | end |
388 | function WorkParticles:loadGroundParticleMapping(superFunc, xmlFile, key, mapping, index, i3dNode) |
389 | if superFunc ~= nil then |
390 | if not superFunc(self, xmlFile, key, mapping, index, i3dNode) then |
391 | return false; |
392 | end |
393 | end |
394 | |
395 | mapping.particleSystem = {}; |
396 | |
397 | local node = Utils.indexToObject(self.components, getXMLString(self.xmlFile, key.."#index")); |
398 | if node == nil then |
399 | print("Warning: Invalid node index '"..getXMLString(self.xmlFile, key.."#index").."' in '"..self.configFileName.."'!"); |
400 | return false; |
401 | end; |
402 | |
403 | local groundRefIndex = getXMLInt(self.xmlFile, key .. "#refNodeIndex"); |
404 | if groundRefIndex == nil or self.groundReferenceNodes[groundRefIndex+1] == nil then |
405 | print("Warning: Invalid refNodeIndex '"..getXMLString(self.xmlFile, key.."#refNodeIndex").."' in '"..self.configFileName.."'!"); |
406 | return false; |
407 | end; |
408 | |
409 | local particleNode = nil |
410 | local particleNodeIndex = getXMLString(self.xmlFile, key.."#particleIndex") |
411 | if particleNodeIndex ~= nil then |
412 | particleNode = Utils.indexToObject(i3dNode, particleNodeIndex); |
413 | if particleNode == nil then |
414 | print("Warning: Invalid particle index '"..particleNodeIndex.."' in '"..self.configFileName.."'!"); |
415 | return false; |
416 | end |
417 | else |
418 | particleNode = node |
419 | |
420 | local particleType = getXMLString(self.xmlFile, key.."#particleType") |
421 | if particleType == nil then |
422 | print("Warning: Missing particleType ("..key..") in '"..self.configFileName.."'!"); |
423 | return false; |
424 | end |
425 | |
426 | local fillType = FillUtil.FILLTYPE_UNKNOWN |
427 | |
428 | local fillTypeStr = getXMLString(self.xmlFile, key.."#fillType") |
429 | if fillTypeStr ~= nil and FillUtil.fillTypeNameToInt[fillTypeStr] ~= nil then |
430 | fillType = FillUtil.fillTypeNameToInt[fillTypeStr] |
431 | end |
432 | |
433 | local particleSystem = MaterialUtil.getParticleSystem(fillType, particleType) |
434 | if particleSystem ~= nil then |
435 | mapping.particleSystem = ParticleUtil.copyParticleSystem(self.xmlFile, key, particleSystem, node) |
436 | end |
437 | end |
438 | |
439 | mapping.node = node; |
440 | mapping.particleNode = particleNode; |
441 | mapping.groundRefNode = self.groundReferenceNodes[groundRefIndex+1]; |
442 | |
443 | return true |
444 | end |