27 | function Leveler.initSpecialization() |
28 | local schema = Vehicle.xmlSchema |
29 | schema:setXMLSpecializationType("Leveler") |
30 | |
31 | local basePath = Leveler.LEVELER_NODE_XML_KEY |
32 | |
33 | schema:register(XMLValueType.NODE_INDEX, basePath .. "#node", "Leveler node") |
34 | |
35 | schema:register(XMLValueType.FLOAT, basePath .. "#width", "Width") |
36 | schema:register(XMLValueType.FLOAT, basePath .. "#zOffset", "Z axis offset", 0) |
37 | schema:register(XMLValueType.FLOAT, basePath .. "#yOffset", "Y axis offset", 0) |
38 | schema:register(XMLValueType.FLOAT, basePath .. "#minDropWidth", "Min. drop width", "half of width") |
39 | schema:register(XMLValueType.FLOAT, basePath .. "#maxDropWidth", "Max. drop width", "width value") |
40 | schema:register(XMLValueType.FLOAT, basePath .. "#minDropDirOffset", "Min. drop direction offset", 0.7) |
41 | schema:register(XMLValueType.FLOAT, basePath .. "#maxDropDirOffset", "Max. drop direction offset", 0.7) |
42 | schema:register(XMLValueType.INT, basePath .. "#numHeightLimitChecks", "Number of height limit checks", 6) |
43 | schema:register(XMLValueType.BOOL, basePath .. "#alignToWorldY", "Defines if the leveler node is aligned to worlds Y axis", true) |
44 | |
45 | schema:register(XMLValueType.BOOL, basePath .. ".smoothing#allowed", "Leveler smoothes while driving backward", true) |
46 | schema:register(XMLValueType.FLOAT, basePath .. ".smoothing#radius", "Smooth ground radius", 0.5) |
47 | schema:register(XMLValueType.FLOAT, basePath .. ".smoothing#overlap", "Radius overlap", 1.7) |
48 | schema:register(XMLValueType.INT, basePath .. ".smoothing#direction", "Smooth direction (if set to '0' it smooths in both directions)", -1) |
49 | |
50 | schema:register(XMLValueType.INT, basePath .. "#fillUnitIndex", "Fill unit index", "Value of vehicle.leveler#fillUnitIndex") |
51 | |
52 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".occlusionAreas.occlusionArea(?)#startNode", "Start node") |
53 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".occlusionAreas.occlusionArea(?)#widthNode", "Width node") |
54 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".occlusionAreas.occlusionArea(?)#heightNode", "Height node") |
55 | |
56 | schema:register(XMLValueType.INT, "vehicle.leveler.pickUpDirection", "Pick up direction", 1) |
57 | schema:register(XMLValueType.INT, "vehicle.leveler#fillUnitIndex", "Fill unit index") |
58 | schema:register(XMLValueType.FLOAT, "vehicle.leveler#maxFillLevelPerMS", "Max. fill level change rate as reference for effect and force", 20) |
59 | |
60 | schema:register(XMLValueType.NODE_INDEX, "vehicle.leveler.force#node", "Force node") |
61 | schema:register(XMLValueType.NODE_INDEX, "vehicle.leveler.force#directionNode", "Force direction node") |
62 | schema:register(XMLValueType.FLOAT, "vehicle.leveler.force#maxForce", "Max. force in kN", 0) |
63 | schema:register(XMLValueType.INT, "vehicle.leveler.force#direction", "Driving direction for appling force", 1) |
64 | |
65 | schema:register(XMLValueType.BOOL, "vehicle.leveler#ignoreFarmlandState", "If set to true the farmland underneath the leveler does not need to be bought to actually work", false) |
66 | |
67 | EffectManager.registerEffectXMLPaths(schema, "vehicle.leveler.effects") |
68 | |
69 | schema:setXMLSpecializationType() |
70 | end |
442 | function Leveler:loadLevelerNodeFromXML(levelerNode, xmlFile, key) |
443 | levelerNode.node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings) |
444 | if levelerNode.node ~= nil then |
445 | local referenceFrame = createTransformGroup("referenceFrame") |
446 | link(getParent(levelerNode.node), referenceFrame) |
447 | setTranslation(referenceFrame, getTranslation(levelerNode.node)) |
448 | setRotation(referenceFrame, getRotation(levelerNode.node)) |
449 | levelerNode.referenceFrame = referenceFrame |
450 | |
451 | levelerNode.zOffset = xmlFile:getValue(key .. "#zOffset", 0) |
452 | levelerNode.yOffset = xmlFile:getValue(key .. "#yOffset", 0) |
453 | levelerNode.width = xmlFile:getValue(key .. "#width") |
454 | levelerNode.halfWidth = levelerNode.width * 0.5 |
455 | |
456 | levelerNode.minDropWidth = xmlFile:getValue(key .. "#minDropWidth", levelerNode.width*0.5) |
457 | levelerNode.halfMinDropWidth = levelerNode.minDropWidth * 0.5 |
458 | levelerNode.maxDropWidth = xmlFile:getValue(key .. "#maxDropWidth", levelerNode.width) |
459 | levelerNode.halfMaxDropWidth = levelerNode.maxDropWidth * 0.5 |
460 | |
461 | levelerNode.minDropDirOffset = xmlFile:getValue(key .. "#minDropDirOffset", 0.7) |
462 | levelerNode.maxDropDirOffset = xmlFile:getValue(key .. "#maxDropDirOffset", 0.7) |
463 | levelerNode.numHeightLimitChecks = xmlFile:getValue(key .. "#numHeightLimitChecks", 6) |
464 | levelerNode.alignToWorldY = xmlFile:getValue(key .. "#alignToWorldY", true) |
465 | |
466 | levelerNode.occlusionAreas = {} |
467 | |
468 | local i = 0 |
469 | while true do |
470 | local baseKey = string.format("%s.occlusionAreas.occlusionArea(%d)", key, i) |
471 | if not xmlFile:hasProperty(baseKey) then |
472 | break |
473 | end |
474 | |
475 | local entry = {} |
476 | entry.startNode = xmlFile:getValue(baseKey .. "#startNode", nil, self.components, self.i3dMappings) |
477 | entry.widthNode = xmlFile:getValue(baseKey .. "#widthNode", nil, self.components, self.i3dMappings) |
478 | entry.heightNode = xmlFile:getValue(baseKey .. "#heightNode", nil, self.components, self.i3dMappings) |
479 | |
480 | if entry.startNode ~= nil and entry.widthNode ~= nil and entry.heightNode ~= nil then |
481 | table.insert(levelerNode.occlusionAreas, entry) |
482 | else |
483 | Logging.xmlWarning(xmlFile, "Failed to load occlustion area '%s'. One or more nodes missing.", baseKey) |
484 | end |
485 | |
486 | i = i + 1 |
487 | end |
488 | |
489 | |
490 | levelerNode.allowsSmoothing = xmlFile:getValue(key .. ".smoothing#allowed", true) |
491 | levelerNode.smoothGroundRadius = xmlFile:getValue(key .. ".smoothing#radius", 0.5) |
492 | levelerNode.smoothOverlap = xmlFile:getValue(key .. ".smoothing#overlap", 1.7) |
493 | levelerNode.smoothDirection = xmlFile:getValue(key .. ".smoothing#direction", -1) |
494 | |
495 | levelerNode.lineOffsetPickUp = nil |
496 | levelerNode.lineOffsetDrop = nil |
497 | |
498 | levelerNode.lastPickUp = 0 |
499 | levelerNode.lastDrop = 0 |
500 | |
501 | levelerNode.fillUnitIndex = xmlFile:getValue(key .. "#fillUnitIndex", self.spec_leveler.fillUnitIndex) |
502 | if not self:getFillUnitExists(levelerNode.fillUnitIndex) then |
503 | Logging.xmlWarning(self.xmlFile, "Unknown fillUnitIndex '%s' for leveler", tostring(levelerNode.fillUnitIndex)) |
504 | return false |
505 | end |
506 | |
507 | return true |
508 | end |
509 | |
510 | return false |
511 | end |
555 | function Leveler.onLevelerRaycastCallback(levelerNode, hitObjectId, x, y, z, distance, nx, ny, nz, subShapeIndex, shapeId, isLast) |
556 | local self = levelerNode.vehicle |
557 | local spec = self.spec_leveler |
558 | |
559 | if hitObjectId ~= 0 then |
560 | if hitObjectId ~= g_currentMission.terrainRootNode then |
561 | levelerNode.raycastHitObject = true |
562 | --#debug drawDebugLine(x, y, z, 1, 0, 0, x, y + 1, z, 1, 0, 0, true) |
563 | end |
564 | end |
565 | |
566 | if isLast then |
567 | if not levelerNode.raycastHitObject then |
568 | local fillLevel = self:getFillUnitFillLevel(levelerNode.fillUnitIndex) |
569 | if fillLevel > 0 then |
570 | local fillType = levelerNode.raycastLastFillType |
571 | local outerRadius = levelerNode.raycastLastRadius |
572 | |
573 | local f = spec.lastFillLevelMovedPct |
574 | local width = MathUtil.lerp(levelerNode.halfMinDropWidth, levelerNode.halfMaxDropWidth, f) |
575 | local dropOffset = MathUtil.lerp(levelerNode.minDropDirOffset, levelerNode.maxDropDirOffset, f) |
576 | |
577 | local terrainHeightUpdater = g_densityMapHeightManager:getTerrainDetailHeightUpdater() |
578 | if terrainHeightUpdater ~= nil then |
579 | for i=1, #levelerNode.occlusionAreas do |
580 | local occlusionArea = levelerNode.occlusionAreas[i] |
581 | |
582 | local ox1, oy1, oz1 = getWorldTranslation(occlusionArea.startNode) |
583 | local ox2, _, oz2 = getWorldTranslation(occlusionArea.widthNode) |
584 | local ox3, _, oz3 = getWorldTranslation(occlusionArea.heightNode) |
585 | |
586 | local x, z, widthX, widthZ, heightX, heightZ = MathUtil.getXZWidthAndHeight(ox1, oz1, ox2, oz2, ox3, oz3) |
587 | |
588 | addDensityMapHeightOcclusionArea(terrainHeightUpdater, x, oy1, z, widthX, oy1, widthZ, heightX, oy1, heightZ, true) |
589 | |
590 | --#debug DebugUtil.drawDebugParallelogram(x, z, widthX, widthZ, heightX, heightZ, 0, 0.5, 0, 0, 0.1) |
591 | end |
592 | end |
593 | |
594 | local sx,sy,sz = localToWorld(levelerNode.node, -width, levelerNode.yOffset, levelerNode.zOffset + dropOffset) |
595 | local ex,ey,ez = localToWorld(levelerNode.node, width, levelerNode.yOffset, levelerNode.zOffset + dropOffset) |
596 | levelerNode.lastDrop2, levelerNode.lineOffsetDrop2 = DensityMapHeightUtil.tipToGroundAroundLine(self, fillLevel, fillType, sx,sy,sz, ex,ey,ez, 0, outerRadius, levelerNode.lineOffsetDrop2, false, nil) |
597 | |
598 | --#debug DebugUtil.drawDebugLine(sx,sy,sz, ex,ey,ez, 0, 1, 1, outerRadius) |
599 | |
600 | if levelerNode.lastDrop2 > 0 then |
601 | local leftOver = fillLevel - levelerNode.lastDrop2 |
602 | if leftOver <= g_densityMapHeightManager:getMinValidLiterValue(fillType) then |
603 | levelerNode.lastDrop2 = fillLevel |
604 | spec.litersToPickup = spec.litersToPickup + leftOver |
605 | end |
606 | self:addFillUnitFillLevel(self:getOwnerFarmId(), levelerNode.fillUnitIndex, -levelerNode.lastDrop2, fillType, ToolType.UNDEFINED, nil) |
607 | end |
608 | end |
609 | end |
610 | end |
611 | end |
200 | function Leveler:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
201 | local spec = self.spec_leveler |
202 | |
203 | if self.isClient then |
204 | local fillType = FillType.UNKNOWN |
205 | for _, levelerNode in pairs(spec.nodes) do |
206 | fillType = self:getFillUnitLastValidFillType(levelerNode.fillUnitIndex) |
207 | if fillType ~= FillType.UNKNOWN then |
208 | break |
209 | end |
210 | end |
211 | |
212 | if fillType ~= FillType.UNKNOWN and spec.lastFillLevelMovedPct > 0 then |
213 | g_effectManager:setFillType(spec.effects, fillType) |
214 | g_effectManager:startEffects(spec.effects) |
215 | |
216 | |
217 | for _, effect in pairs(spec.effects) do |
218 | if effect:isa(LevelerEffect) or effect:isa(SnowPlowMotionPathEffect) then |
219 | effect:setFillLevel(spec.lastFillLevelMovedPct) |
220 | effect:setLastVehicleSpeed(self.movingDirection * self:getLastSpeed()) |
221 | end |
222 | end |
223 | else |
224 | g_effectManager:stopEffects(spec.effects) |
225 | end |
226 | end |
227 | |
228 | if self.isServer then |
229 | for _, levelerNode in pairs(spec.nodes) do |
230 | local x0,y0,z0 = localToWorld(levelerNode.node, -levelerNode.halfWidth, levelerNode.yOffset, levelerNode.maxDropDirOffset) |
231 | local x1,y1,z1 = localToWorld(levelerNode.node, levelerNode.halfWidth, levelerNode.yOffset, levelerNode.maxDropDirOffset) |
232 | if not spec.ignoreFarmlandState then |
233 | local ownerFarmId = self:getOwnerFarmId() |
234 | if not g_farmlandManager:getCanAccessLandAtWorldPosition(ownerFarmId, x0, z0) or |
235 | not g_farmlandManager:getCanAccessLandAtWorldPosition(ownerFarmId, x1, z1) then |
236 | break |
237 | end |
238 | end |
239 | |
240 | local pickedUpFillLevel = 0 |
241 | local fillType = self:getFillUnitFillType(levelerNode.fillUnitIndex) |
242 | local fillLevel = self:getFillUnitFillLevel(levelerNode.fillUnitIndex) |
243 | |
244 | if fillType == FillType.UNKNOWN or fillLevel < g_densityMapHeightManager:getMinValidLiterValue(fillType) + 0.001 then |
245 | local newFillType = DensityMapHeightUtil.getFillTypeAtLine(x0,y0,z0, x1,y1,z1, 0.5*levelerNode.maxDropDirOffset) |
246 | if newFillType ~= FillType.UNKNOWN and newFillType ~= fillType then |
247 | if self:getFillUnitSupportsFillType(levelerNode.fillUnitIndex, newFillType) then |
248 | self:addFillUnitFillLevel(self:getOwnerFarmId(), levelerNode.fillUnitIndex, -math.huge) |
249 | fillType = newFillType |
250 | end |
251 | end |
252 | end |
253 | local heightType = g_densityMapHeightManager:getDensityMapHeightTypeByFillTypeIndex(fillType) |
254 | |
255 | if fillType ~= FillType.UNKNOWN and heightType ~= nil then |
256 | local innerRadius = 0.5 |
257 | local outerRadius = 2 |
258 | local capacity = self:getFillUnitCapacity(levelerNode.fillUnitIndex) |
259 | |
260 | -- limit the leveler node Y direction to the world Y (So the node + offset can be higher as the node but cannot dig into the ground when facing downwards) |
261 | local dirY = 0 |
262 | if levelerNode.alignToWorldY then |
263 | local dirX, dirZ |
264 | dirX, dirY, dirZ = localDirectionToWorld(levelerNode.referenceFrame, 0, 0, 1) |
265 | I3DUtil.setWorldDirection(levelerNode.node, dirX, math.max(dirY, 0), dirZ, 0, 1, 0) |
266 | end |
267 | --#debug DebugUtil.drawDebugNode(levelerNode.node, "levelerNode", false) |
268 | |
269 | -- pick up at node |
270 | if self:getIsLevelerPickupNodeActive(levelerNode) then |
271 | if spec.pickUpDirection == self.movingDirection and self.lastSpeed > 0.0001 then |
272 | local sx,sy,sz = localToWorld(levelerNode.node, -levelerNode.halfWidth, levelerNode.yOffset, levelerNode.zOffset) |
273 | local ex,ey,ez = localToWorld(levelerNode.node, levelerNode.halfWidth, levelerNode.yOffset, levelerNode.zOffset) |
274 | |
275 | --#debug DebugUtil.drawDebugLine(sx, sy, sz, ex, ey, ez, 0, 1, 0) |
276 | |
277 | if dirY >= 0 then |
278 | local _, sy2, _ = localToWorld(levelerNode.node, -levelerNode.halfWidth, levelerNode.yOffset, levelerNode.zOffset + innerRadius) |
279 | local _, ey2, _ = localToWorld(levelerNode.node, levelerNode.halfWidth, levelerNode.yOffset, levelerNode.zOffset + innerRadius) |
280 | |
281 | sy = math.max(sy, sy2) |
282 | ey = math.max(ey, ey2) |
283 | end |
284 | |
285 | fillLevel = self:getFillUnitFillLevel(levelerNode.fillUnitIndex) |
286 | local delta = -(capacity-fillLevel) |
287 | local numHeightLimitChecks = levelerNode.numHeightLimitChecks |
288 | if numHeightLimitChecks > 0 then |
289 | local movementY = 0 |
290 | for i=0,numHeightLimitChecks do |
291 | local t = i/numHeightLimitChecks |
292 | local xi = sx + (ex-sx)*t |
293 | local yi = sy + (ey-sy)*t |
294 | local zi = sz + (ez-sz)*t |
295 | local hi = DensityMapHeightUtil.getHeightAtWorldPos(xi,yi,zi) |
296 | movementY = math.max(movementY, hi-0.05 - yi) -- limit to 5cm below surface |
297 | end |
298 | if movementY > 0 then |
299 | sy = sy+movementY |
300 | ey = ey+movementY |
301 | end |
302 | end |
303 | |
304 | levelerNode.lastPickUp, levelerNode.lineOffsetPickUp = DensityMapHeightUtil.tipToGroundAroundLine(self, delta, fillType, sx,sy,sz, ex,ey,ez, innerRadius, outerRadius, levelerNode.lineOffsetPickUp, true, nil) |
305 | |
306 | --#debug DebugUtil.drawDebugLine(sx, sy, sz, ex, ey, ez, 1, 0, 0, innerRadius) |
307 | |
308 | if levelerNode.lastPickUp < 0 then |
309 | if self.notifiyBunkerSilo ~= nil then |
310 | self:notifiyBunkerSilo(levelerNode.lastPickUp, fillType, (sx+ex) * 0.5, (sy+ey) * 0.5, (sz+ez) * 0.5) |
311 | end |
312 | |
313 | levelerNode.lastPickUp = levelerNode.lastPickUp + spec.litersToPickup |
314 | spec.litersToPickup = 0 |
315 | |
316 | self:addFillUnitFillLevel(self:getOwnerFarmId(), levelerNode.fillUnitIndex, -levelerNode.lastPickUp, fillType, ToolType.UNDEFINED, nil) |
317 | pickedUpFillLevel = levelerNode.lastPickUp |
318 | end |
319 | end |
320 | end |
321 | |
322 | local lastPickUpPerMS = -pickedUpFillLevel |
323 | |
324 | spec.lastFillLevelMovedBuffer = spec.lastFillLevelMovedBuffer + lastPickUpPerMS |
325 | spec.lastFillLevelMovedBufferTimer = spec.lastFillLevelMovedBufferTimer + dt |
326 | if spec.lastFillLevelMovedBufferTimer > spec.lastFillLevelMovedBufferTime then |
327 | spec.lastFillLevelMovedTarget = spec.lastFillLevelMovedBuffer / spec.lastFillLevelMovedBufferTimer |
328 | |
329 | spec.lastFillLevelMovedBufferTimer = 0 |
330 | spec.lastFillLevelMovedBuffer = 0 |
331 | end |
332 | |
333 | if self.movingDirection < 0 and self.lastSpeed * 3600 > 0.5 then |
334 | spec.lastFillLevelMovedBuffer = 0 |
335 | end |
336 | |
337 | -- drop at node |
338 | fillLevel = self:getFillUnitFillLevel(levelerNode.fillUnitIndex) |
339 | if fillLevel > 0 then |
340 | local f = (fillLevel/capacity) |
341 | local width = MathUtil.lerp(levelerNode.halfMinDropWidth, levelerNode.halfMaxDropWidth, f) |
342 | |
343 | local sx,sy,sz = localToWorld(levelerNode.node, -width, levelerNode.yOffset, levelerNode.zOffset) |
344 | local ex,ey,ez = localToWorld(levelerNode.node, width, levelerNode.yOffset, levelerNode.zOffset) |
345 | |
346 | local yOffset = -0.15 |
347 | |
348 | levelerNode.lastDrop1, levelerNode.lineOffsetDrop1 = DensityMapHeightUtil.tipToGroundAroundLine(self, fillLevel, fillType, sx,sy+yOffset,sz, ex,ey+yOffset,ez, innerRadius, outerRadius, levelerNode.lineOffsetDrop1, true, nil) |
349 | |
350 | --#debug DebugUtil.drawDebugLine(sx,sy+yOffset,sz, ex,ey+yOffset,ez, 1, 1, 1, innerRadius) |
351 | |
352 | if levelerNode.lastDrop1 > 0 then |
353 | local leftOver = fillLevel - levelerNode.lastDrop1 |
354 | if leftOver <= g_densityMapHeightManager:getMinValidLiterValue(fillType) then |
355 | levelerNode.lastDrop1 = fillLevel |
356 | spec.litersToPickup = spec.litersToPickup + leftOver |
357 | end |
358 | self:addFillUnitFillLevel(self:getOwnerFarmId(), levelerNode.fillUnitIndex, -levelerNode.lastDrop1, fillType, ToolType.UNDEFINED, nil) |
359 | end |
360 | end |
361 | |
362 | -- drop further at front |
363 | fillLevel = self:getFillUnitFillLevel(levelerNode.fillUnitIndex) |
364 | |
365 | if fillLevel > 0 then |
366 | local dropOffset = MathUtil.lerp(levelerNode.minDropDirOffset, levelerNode.maxDropDirOffset, spec.lastFillLevelMovedPct) |
367 | |
368 | local wx, wy, wz = localToWorld(levelerNode.node, 0, levelerNode.yOffset, 0) |
369 | local tx, ty, tz = localToWorld(levelerNode.node, 0, levelerNode.yOffset, levelerNode.zOffset + dropOffset) |
370 | |
371 | levelerNode.raycastLastFillType = fillType |
372 | levelerNode.raycastLastRadius = outerRadius |
373 | levelerNode.raycastHitObject = false |
374 | local rDirX, rDirY, rDirZ = tx-wx, ty-wy, tz-wz |
375 | local distance = MathUtil.vector3Length(rDirX, rDirY, rDirZ) |
376 | rDirX, rDirY, rDirZ = MathUtil.vector3Normalize(rDirX, rDirY, rDirZ) |
377 | raycastAll(wx, wy, wz, rDirX, rDirY, rDirZ, "onLevelerRaycastCallback", distance, levelerNode, CollisionFlag.STATIC_OBJECTS, false, true) |
378 | |
379 | --#debug drawDebugLine(wx, wy, wz, 1, 0, 0, wx+rDirX*distance, wy+rDirY*distance, wz+rDirZ*distance, 0, 1, 0, true) |
380 | end |
381 | else |
382 | spec.lastFillLevelMovedBuffer = 0 |
383 | spec.lastFillLevelMovedTarget = 0 |
384 | end |
385 | |
386 | -- call fill level changed callack to inform bunker silo about change |
387 | if pickedUpFillLevel < 0 and fillType ~= FillType.UNKNOWN then |
388 | self:notifiyBunkerSilo(pickedUpFillLevel, fillType) |
389 | end |
390 | |
391 | if levelerNode.allowsSmoothing and (levelerNode.smoothDirection == 0 or self.movingDirection == levelerNode.smoothDirection) then |
392 | local smoothAmount = 0 |
393 | if self.lastSpeedReal > 0.0002 then -- start smoothing if driving faster than 0.7km/h |
394 | smoothAmount = spec.smoothAccumulation + math.max(self.lastMovedDistance * 0.5, 0.0003*dt) -- smooth 1.2m per meter driving or at least 0.3m/s |
395 | local rounded = DensityMapHeightUtil.getRoundedHeightValue(smoothAmount) |
396 | spec.smoothAccumulation = smoothAmount - rounded |
397 | else |
398 | spec.smoothAccumulation = 0 |
399 | end |
400 | |
401 | if smoothAmount > 0 then |
402 | DensityMapHeightUtil.smoothAroundLine(levelerNode.node, levelerNode.width, levelerNode.smoothGroundRadius, levelerNode.smoothOverlap, smoothAmount) |
403 | end |
404 | end |
405 | end |
406 | |
407 | local smoothFactor = 0.05 |
408 | if spec.lastFillLevelMovedTarget == 0 then |
409 | smoothFactor = 0.2 |
410 | end |
411 | |
412 | spec.lastFillLevelMoved = spec.lastFillLevelMoved * (1-smoothFactor) + spec.lastFillLevelMovedTarget * smoothFactor |
413 | if spec.lastFillLevelMoved < 0.005 then |
414 | spec.lastFillLevelMoved = 0 |
415 | end |
416 | |
417 | local oldPercentage = spec.lastFillLevelMovedPct |
418 | spec.lastFillLevelMovedPct = math.max(math.min(spec.lastFillLevelMoved / spec.maxFillLevelPerMS, 1), 0) |
419 | |
420 | if spec.lastFillLevelMovedPct ~= oldPercentage then |
421 | self:raiseDirtyFlags(spec.dirtyFlag) |
422 | end |
423 | |
424 | if spec.forceNode ~= nil then |
425 | if self.movingDirection == spec.forceDir and spec.lastFillLevelMoved > 0 then |
426 | spec.lastForce = -spec.maxForce * spec.lastFillLevelMovedPct |
427 | local dx, dy, dz = localDirectionToWorld(spec.forceDirNode, 0, 0, spec.lastForce) |
428 | local px, py, pz = getCenterOfMass(spec.forceNode) |
429 | |
430 | addForce(spec.forceNode, dx, dy, dz, px, py, pz, true) |
431 | end |
432 | end |
433 | end |
434 | end |