LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

ConveyorBelt

Description
Class for conveyor belts to control unloading start time and unloading effects
Functions

getConveyorBeltFillLevel

Description
Definition
getConveyorBeltFillLevel()
Code
290function ConveyorBelt:getConveyorBeltFillLevel()
291 local spec = self.spec_conveyorBelt
292 local fillLevel = self:getFillUnitFillLevel(spec.fillUnitIndex)
293 if self.getCurrentDischargeNode ~= nil then
294 local currentDischargeNode = self:getCurrentDischargeNode()
295 local object = currentDischargeNode.dischargeHitObject
296 if object ~= nil and object.getConveyorBeltFillLevel ~= nil then
297 fillLevel = fillLevel + object:getConveyorBeltFillLevel()
298 end
299 end
300
301 return fillLevel
302end

getConveyorBeltTargetObject

Description
Definition
getConveyorBeltTargetObject()
Code
306function ConveyorBelt:getConveyorBeltTargetObject()
307 if self.getCurrentDischargeNode ~= nil then
308 local currentDischargeNode = self:getCurrentDischargeNode()
309 local object, targetFillUnitIndex = currentDischargeNode.dischargeHitObject, currentDischargeNode.dischargeHitObjectUnitIndex
310 if object ~= nil then
311 if object.getConveyorBeltTargetObject ~= nil then
312 return object:getConveyorBeltTargetObject()
313 else
314 return object, targetFillUnitIndex
315 end
316 end
317 end
318
319 return nil
320end

getDischargeNodeEmptyFactor

Description
Definition
getDischargeNodeEmptyFactor()
Code
342function ConveyorBelt:getDischargeNodeEmptyFactor(superFunc, dischargeNode)
343 local spec = self.spec_conveyorBelt
344 local parentFactor = superFunc(self, dischargeNode)
345
346 if spec.dischargeNodeIndex == dischargeNode.index then
347 if spec.morphEndPos == 1 then
348 return spec.emptyFactor
349 else
350 return 0
351 end
352 end
353
354 return parentFactor
355end

getFillUnitAllowsFillType

Description
Definition
getFillUnitAllowsFillType()
Code
385function ConveyorBelt:getFillUnitAllowsFillType(superFunc, fillUnitIndex, fillType)
386 if not superFunc(self, fillUnitIndex, fillType) then
387 return false
388 end
389
390 if self.getCurrentDischargeNode ~= nil then
391 local currentDischargeNode = self:getCurrentDischargeNode()
392 if currentDischargeNode.fillUnitIndex == fillUnitIndex then
393 local object, targetFillUnitIndex = currentDischargeNode.dischargeHitObject, currentDischargeNode.dischargeHitObjectUnitIndex
394 if object ~= nil and object.getFillUnitAllowsFillType ~= nil and targetFillUnitIndex ~= nil then
395 if currentDischargeNode.fillTypeConverter ~= nil then
396 local conversion = currentDischargeNode.fillTypeConverter[fillType]
397 if conversion ~= nil then
398 if object:getFillUnitAllowsFillType(targetFillUnitIndex, conversion.targetFillTypeIndex) then
399 return true
400 end
401 end
402 end
403
404 return object:getFillUnitAllowsFillType(targetFillUnitIndex, fillType)
405 end
406 end
407 end
408
409 return true
410end

getFillUnitFreeCapacity

Description
Definition
getFillUnitFreeCapacity()
Code
414function ConveyorBelt:getFillUnitFreeCapacity(superFunc, fillUnitIndex, fillTypeIndex, farmId)
415 local freeCapacity = superFunc(self, fillUnitIndex, fillTypeIndex, farmId)
416
417 if self.getCurrentDischargeNode ~= nil then
418 local currentDischargeNode = self:getCurrentDischargeNode()
419 if currentDischargeNode.fillUnitIndex == fillUnitIndex then
420 local object, targetFillUnitIndex = currentDischargeNode.dischargeHitObject, currentDischargeNode.dischargeHitObjectUnitIndex
421 if object ~= nil and object.getFillUnitFreeCapacity ~= nil and targetFillUnitIndex ~= nil then
422 return freeCapacity + object:getFillUnitFreeCapacity(targetFillUnitIndex, fillTypeIndex, farmId)
423 end
424 end
425 end
426
427 return freeCapacity
428end

getIsEnterable

Description
Definition
getIsEnterable()
Code
379function ConveyorBelt:getIsEnterable(superFunc)
380 return (self.getAttacherVehicle == nil or self:getAttacherVehicle() == nil) and superFunc(self)
381end

getLoadTriggerMaxFillSpeed

Description
Definition
getLoadTriggerMaxFillSpeed()
Code
324function ConveyorBelt:getLoadTriggerMaxFillSpeed()
325 local maxSpeed = math.huge
326 if self.getCurrentDischargeNode ~= nil then
327 local currentDischargeNode = self:getCurrentDischargeNode()
328 maxSpeed = currentDischargeNode.emptySpeed
329 local object = currentDischargeNode.dischargeHitObject
330 if object ~= nil then
331 if object.getLoadTriggerMaxFillSpeed ~= nil then
332 maxSpeed = math.min(object:getLoadTriggerMaxFillSpeed(), maxSpeed)
333 end
334 end
335 end
336
337 return maxSpeed
338end

handleDischarge

Description
Definition
handleDischarge()
Code
369function ConveyorBelt:handleDischarge(superFunc, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel)
370 local spec = self.spec_conveyorBelt
371 -- do nothing if it is conveyor dischargenode
372 if dischargeNode.index ~= spec.dischargeNodeIndex then
373 superFunc(self, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel)
374 end
375end

handleDischargeOnEmpty

Description
Definition
handleDischargeOnEmpty()
Code
359function ConveyorBelt:handleDischargeOnEmpty(superFunc, dischargeNode)
360 local spec = self.spec_conveyorBelt
361 -- do nothing if conveyorBelt dischargenode is empty
362 if dischargeNode.index ~= spec.dischargeNodeIndex then
363 superFunc(self, dischargeNode)
364 end
365end

initSpecialization

Description
Definition
initSpecialization()
Code
23function ConveyorBelt.initSpecialization()
24 local schema = Vehicle.xmlSchema
25 schema:setXMLSpecializationType("ConveyorBelt")
26
27 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.conveyorBelt.animationNodes")
28 EffectManager.registerEffectXMLPaths(schema, "vehicle.conveyorBelt.effects")
29
30 schema:register(XMLValueType.INT, "vehicle.conveyorBelt#dischargeNodeIndex", "Discharge node index", 1)
31 schema:register(XMLValueType.FLOAT, "vehicle.conveyorBelt#startPercentage", "Start unloading percentage", 0.9)
32
33 schema:register(XMLValueType.NODE_INDEX, "vehicle.conveyorBelt.offset(?)#movingToolNode", "Moving tool node")
34 schema:register(XMLValueType.INT, "vehicle.conveyorBelt.offset(?).effect(?)#index", "Index of effect", 0)
35 schema:register(XMLValueType.FLOAT, "vehicle.conveyorBelt.offset(?).effect(?)#minOffset", "Min. offset", 0)
36 schema:register(XMLValueType.FLOAT, "vehicle.conveyorBelt.offset(?).effect(?)#maxOffset", "Max. offset", 1)
37 schema:register(XMLValueType.BOOL, "vehicle.conveyorBelt.offset(?).effect(?)#inverted", "Is inverted", false)
38
39 SoundManager.registerSampleXMLPaths(schema, "vehicle.conveyorBelt.sounds", "belt")
40
41 schema:setXMLSpecializationType()
42end

onDelete

Description
Called on deleting
Definition
onDelete()
Code
197function ConveyorBelt:onDelete()
198 local spec = self.spec_conveyorBelt
199 g_effectManager:deleteEffects(spec.effects)
200 g_animationManager:deleteAnimations(spec.animationNodes)
201 g_soundManager:deleteSamples(spec.samples)
202end

onFillUnitFillLevelChanged

Description
Definition
onFillUnitFillLevelChanged()
Code
432function ConveyorBelt:onFillUnitFillLevelChanged(fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta)
433 local spec = self.spec_conveyorBelt
434 if spec.fillUnitIndex == fillUnitIndex then
435 local fillLevel = self:getFillUnitFillLevel(fillUnitIndex)
436
437 if fillLevelDelta > 0 then
438 spec.morphStartPos = 0
439 spec.morphEndPos = math.max(spec.morphEndPos, fillLevel / self:getFillUnitCapacity(fillUnitIndex))
440 spec.isEffectDirty = true
441 end
442
443 if fillLevelDelta ~= 0 then
444 spec.scrollUpdateTime = 100
445 end
446
447 if fillLevel == 0 then
448 g_effectManager:stopEffects(spec.effects)
449 spec.morphStartPos = 0
450 spec.morphEndPos = 0
451 spec.isEffectDirty = true
452 else
453 g_effectManager:setFillType(spec.effects, fillType)
454 g_effectManager:startEffects(spec.effects)
455 end
456 end
457end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
77function ConveyorBelt:onLoad(savegame)
78 local spec = self.spec_conveyorBelt
79
80 if self.isClient then
81 spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.conveyorBelt.animationNodes", self.components, self, self.i3dMappings)
82
83 spec.samples = {}
84 spec.samples.belt = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.conveyorBelt.sounds", "belt", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
85 end
86
87 spec.effects = g_effectManager:loadEffect(self.xmlFile, "vehicle.conveyorBelt.effects", self.components, self, self.i3dMappings)
88 spec.currentDelay = 0
89 table.sort(spec.effects, function(effect1, effect2) return effect1.startDelay < effect2.startDelay end)
90
91 for _, effect in pairs(spec.effects) do
92 if effect.planeFadeTime ~= nil then
93 spec.currentDelay = spec.currentDelay + effect.planeFadeTime
94 end
95 if effect.setScrollUpdate ~= nil then
96 effect:setScrollUpdate(false)
97 end
98 end
99 spec.maxDelay = spec.currentDelay
100
101 spec.morphStartPos = 0
102 spec.morphEndPos = 0
103 spec.isEffectDirty = true
104 spec.emptyFactor = 1
105 spec.scrollUpdateTime = 0
106 spec.lastScrollUpdate = false
107
108 spec.dischargeNodeIndex = self.xmlFile:getValue("vehicle.conveyorBelt#dischargeNodeIndex", 1)
109 self:setCurrentDischargeNodeIndex(spec.dischargeNodeIndex)
110 local dischargeNode = self:getDischargeNodeByIndex(spec.dischargeNodeIndex)
111 local capacity = self:getFillUnitCapacity(dischargeNode.fillUnitIndex)
112 spec.fillUnitIndex = dischargeNode.fillUnitIndex
113 spec.startFillLevel = capacity * self.xmlFile:getValue("vehicle.conveyorBelt#startPercentage", 0.9)
114
115 local i = 0
116 while true do
117 local key = string.format("vehicle.conveyorBelt.offset(%d)", i)
118 if not self.xmlFile:hasProperty(key) then
119 break
120 end
121
122 local movingToolNode = self.xmlFile:getValue(key.."#movingToolNode", nil, self.components, self.i3dMappings)
123 if movingToolNode ~= nil then
124 if spec.offsets == nil then
125 spec.offsets = {}
126 end
127
128 local offset = {}
129 offset.lastState = 0
130 offset.movingToolNode = movingToolNode
131 offset.effects = {}
132 local j = 0
133 while true do
134 local effectKey = string.format(key..".effect(%d)", j)
135 if not self.xmlFile:hasProperty(effectKey) then
136 break
137 end
138
139 local effectIndex = self.xmlFile:getValue(effectKey.."#index", 0)
140 local effect = spec.effects[effectIndex]
141 if effect ~= nil and effect.setOffset ~= nil then
142 local entry = {}
143 entry.effect = effect
144 entry.minValue = self.xmlFile:getValue(effectKey.."#minOffset", 0) * 1000
145 entry.maxValue = self.xmlFile:getValue(effectKey.."#maxOffset", 1) * 1000
146 entry.inverted = self.xmlFile:getValue(effectKey.."#inverted", false)
147 table.insert(offset.effects, entry)
148 else
149 Logging.xmlWarning(self.xmlFile, "Effect index '%d' not found at '%s'!", effectIndex, effectKey)
150 end
151 j = j + 1
152 end
153
154 table.insert(spec.offsets, offset)
155 else
156 Logging.xmlWarning(self.xmlFile, "Missing movingToolNode for conveyor offset '%s'!", key)
157 end
158 i = i + 1
159 end
160end

onMovingToolChanged

Description
Definition
onMovingToolChanged()
Code
461function ConveyorBelt:onMovingToolChanged(movingTool, speed, dt)
462 local spec = self.spec_conveyorBelt
463 if spec.offsets ~= nil then
464 local offset = spec.movingToolToOffset[movingTool]
465
466 if offset ~= nil then
467 local state = Cylindered.getMovingToolState(self, movingTool)
468 if state ~= offset.lastState then
469 local updateDelay = false
470
471 for _, entry in pairs(offset.effects) do
472 local effectState = state
473 if entry.inverted then
474 effectState = 1 - effectState
475 end
476
477 entry.effect:setOffset(MathUtil.lerp(entry.minValue, entry.maxValue, effectState))
478 updateDelay = true
479 spec.isEffectDirty = true
480 end
481
482 if updateDelay then
483 spec.currentDelay = 0
484 for _, effect in pairs(spec.effects) do
485 if effect.planeFadeTime ~= nil then
486 spec.currentDelay = spec.currentDelay + effect.planeFadeTime - effect.offset
487 end
488 end
489 end
490
491 offset.lastState = state
492 end
493 end
494 end
495end

onPostLoad

Description
Definition
onPostLoad()
Code
164function ConveyorBelt:onPostLoad(savegame)
165 local spec = self.spec_conveyorBelt
166
167 -- we need to check movingTool in post load to avoid order dependencies
168 if spec.offsets ~= nil then
169 if self.getMovingToolByNode ~= nil then
170 spec.movingToolToOffset = {}
171 for i=#spec.offsets, 1, -1 do
172 local offset = spec.offsets[i]
173 local movingTool = self:getMovingToolByNode(offset.movingToolNode)
174 if movingTool ~= nil then
175 offset.movingTool = movingTool
176 spec.movingToolToOffset[movingTool] = offset
177 ConveyorBelt.onMovingToolChanged(self, movingTool, 0, 0)
178 else
179 Logging.xmlWarning(self.xmlFile, "No movingTool node '%s' defined for conveyor offset '%d'!", getName(offset.movingToolNode), i)
180 table.remove(spec.offsets, i)
181 end
182 end
183
184 if #spec.offsets == 0 then
185 spec.offsets = nil
186 spec.movingToolToOffset = nil
187 end
188 else
189 Logging.xmlError(self.xmlFile, "'Cylindered' specialization is required to use conveyorBelt offsets!")
190 spec.offsets = nil
191 end
192 end
193end

onUpdateTick

Description
Called on update tick
Definition
onUpdateTick(float dt, boolean isActiveForInput, boolean isSelected)
Arguments
floatdttime since last call in ms
booleanisActiveForInputtrue if vehicle is active for input
booleanisSelectedtrue if vehicle is selected
Code
209function ConveyorBelt:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
210 local spec = self.spec_conveyorBelt
211
212 local doScrollUpdate = spec.scrollUpdateTime > 0
213 if doScrollUpdate ~= spec.lastScrollUpdate then
214 if self.isClient then
215 if doScrollUpdate then
216 g_animationManager:startAnimations(spec.animationNodes)
217 g_soundManager:playSample(spec.samples.belt)
218 else
219 g_animationManager:stopAnimations(spec.animationNodes)
220 g_soundManager:stopSample(spec.samples.belt)
221 end
222
223 for _, effect in pairs(spec.effects) do
224 if effect.setScrollUpdate ~= nil then
225 effect:setScrollUpdate(doScrollUpdate)
226 end
227 end
228 end
229
230 spec.lastScrollUpdate = doScrollUpdate
231 end
232 spec.scrollUpdateTime = math.max(spec.scrollUpdateTime - dt, 0)
233
234 local isBeltActive = self:getDischargeState() ~= Dischargeable.DISCHARGE_STATE_OFF
235 if isBeltActive then
236 local fillLevel = self:getFillUnitFillLevel(spec.fillUnitIndex)
237 if fillLevel > 0.0001 then
238 local movedFactor = dt / spec.currentDelay
239 spec.morphStartPos = MathUtil.clamp(spec.morphStartPos + movedFactor, 0, 1)
240 spec.morphEndPos = MathUtil.clamp(spec.morphEndPos + movedFactor, 0, 1)
241
242 -- we calculate the empty factor based on visual effect mesh and filllevel to get a smooth transition
243 local fillFactor = fillLevel/self:getFillUnitCapacity(spec.fillUnitIndex)
244 local visualFactor = spec.morphEndPos-spec.morphStartPos
245
246 spec.emptyFactor = 1
247 if visualFactor > fillFactor then
248 spec.emptyFactor = MathUtil.clamp(fillFactor/visualFactor, 0, 1)
249 else
250 local offset = fillFactor - visualFactor
251 spec.offset = offset
252 spec.morphStartPos = MathUtil.clamp(spec.morphStartPos - (offset/((1-spec.morphStartPos)*spec.currentDelay))*dt , 0, 1)
253 end
254
255 spec.isEffectDirty = true
256 spec.scrollUpdateTime = dt * 3
257 end
258 end
259
260 if doScrollUpdate then
261 self:raiseActive()
262 end
263
264 if self.isClient then
265 if spec.isEffectDirty then
266 for _, effect in pairs(spec.effects) do
267 if effect.setMorphPosition ~= nil then
268 local effectStart = effect.startDelay/spec.currentDelay
269 local effectEnd = (effect.startDelay+effect.planeFadeTime-effect.offset)/spec.currentDelay
270 local offsetFactor = effect.offset/effect.planeFadeTime
271
272 local startMorphFactor = (spec.morphStartPos-effectStart)/(effectEnd-effectStart)
273 local startMorph = MathUtil.clamp(offsetFactor + startMorphFactor*(1-offsetFactor), offsetFactor, 1)
274
275 local endMorphFactor = (spec.morphEndPos-effectStart)/(effectEnd-effectStart)
276 local endMorph = MathUtil.clamp(offsetFactor + endMorphFactor*(1-offsetFactor), offsetFactor, 1)
277
278 --renderText(0.6, 0.8-i*0.015, 0.012, string.format("%d: effectStart %.4f effectEnd %.4f -> startMorph %.4f endMorph %.4f | offset %.4f | %.4f %.4f", i, effectStart, effectEnd, startMorph, endMorph, effect.offset/effect.planeFadeTime, (spec.morphStartPos-effectStart)/(effectEnd-effectStart), (spec.morphEndPos-effectStart)/(effectEnd-effectStart)))
279 effect:setMorphPosition(startMorph, endMorph)
280 end
281 end
282 spec.isEffectDirty = false
283 end
284 end
285end

prerequisitesPresent

Description
Checks if all prerequisite specializations are loaded
Definition
prerequisitesPresent(table specializations)
Arguments
tablespecializationsspecializations
Return Values
booleanhasPrerequisitetrue if all prerequisite specializations are loaded
Code
17function ConveyorBelt.prerequisitesPresent(specializations)
18 return SpecializationUtil.hasSpecialization(Dischargeable, specializations)
19end

registerEventListeners

Description
Definition
registerEventListeners()
Code
65function ConveyorBelt.registerEventListeners(vehicleType)
66 SpecializationUtil.registerEventListener(vehicleType, "onLoad", ConveyorBelt)
67 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", ConveyorBelt)
68 SpecializationUtil.registerEventListener(vehicleType, "onDelete", ConveyorBelt)
69 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", ConveyorBelt)
70 SpecializationUtil.registerEventListener(vehicleType, "onFillUnitFillLevelChanged", ConveyorBelt)
71 SpecializationUtil.registerEventListener(vehicleType, "onMovingToolChanged", ConveyorBelt)
72end

registerFunctions

Description
Definition
registerFunctions()
Code
46function ConveyorBelt.registerFunctions(vehicleType)
47 SpecializationUtil.registerFunction(vehicleType, "getConveyorBeltFillLevel", ConveyorBelt.getConveyorBeltFillLevel)
48 SpecializationUtil.registerFunction(vehicleType, "getConveyorBeltTargetObject", ConveyorBelt.getConveyorBeltTargetObject)
49 SpecializationUtil.registerFunction(vehicleType, "getLoadTriggerMaxFillSpeed", ConveyorBelt.getLoadTriggerMaxFillSpeed)
50end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
54function ConveyorBelt.registerOverwrittenFunctions(vehicleType)
55 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDischargeNodeEmptyFactor", ConveyorBelt.getDischargeNodeEmptyFactor)
56 SpecializationUtil.registerOverwrittenFunction(vehicleType, "handleDischargeOnEmpty", ConveyorBelt.handleDischargeOnEmpty)
57 SpecializationUtil.registerOverwrittenFunction(vehicleType, "handleDischarge", ConveyorBelt.handleDischarge)
58 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsEnterable", ConveyorBelt.getIsEnterable)
59 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitAllowsFillType", ConveyorBelt.getFillUnitAllowsFillType)
60 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitFreeCapacity", ConveyorBelt.getFillUnitFreeCapacity)
61end

updateDebugValues

Description
Definition
updateDebugValues()
Code
499function ConveyorBelt:updateDebugValues(values)
500 local spec = self.spec_conveyorBelt
501
502 table.insert(values, {name="offset", value=spec.offset})
503 table.insert(values, {name="morphStartPos", value=spec.morphStartPos})
504 table.insert(values, {name="morphEndPos", value=spec.morphEndPos})
505end