LUADOC - Farming Simulator 19

Script v1.7.1.0

Engine v1.7.1.0

Foundation Reference

Trailer

Description
Specialization for trailers providing tipping animation and tip side selection functionlity
Functions

actionEventToggleTipSide

Description
Definition
actionEventToggleTipSide()
Code
560function Trailer.actionEventToggleTipSide(self, actionName, inputValue, callbackState, isAnalog)
561 local spec = self.spec_trailer
562
563 if self:getCanTogglePreferdTipSide() then
564 local tipSideIndex = spec.preferedTipSideIndex + 1
565 if tipSideIndex > spec.tipSideCount then
566 tipSideIndex = 1
567 end
568 self:setPreferedTipSide(tipSideIndex)
569 end
570end

endTipping

Description
Definition
endTipping()
Code
336function Trailer:endTipping(noEventSend)
337 local spec = self.spec_trailer
338
339 local tipSide = spec.tipSides[spec.currentTipSideIndex]
340 if tipSide ~= nil then
341 if tipSide.doorAnimation.name ~= nil then
342 if tipSide.doorAnimation.delayedClosing then
343 local animTime = self:getAnimationTime(tipSide.doorAnimation.name)
344 self:playAnimation(tipSide.doorAnimation.name, -tipSide.doorAnimation.speedScale, animTime, true)
345 end
346 end
347 end
348
349 spec.tipState = Trailer.TIPSTATE_CLOSED
350 spec.currentTipSideIndex = nil
351
352 SpecializationUtil.raiseEvent(self, "onEndTipping")
353end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
524function Trailer:getCanBeSelected(superFunc)
525 return true
526end

getCanDischargeToGround

Description
Definition
getCanDischargeToGround()
Code
486function Trailer:getCanDischargeToGround(superFunc, dischargeNode)
487 local canTip = superFunc(self, dischargeNode)
488 if dischargeNode ~= nil then
489 local spec = self.spec_trailer
490 local tipSide = spec.dischargeNodeIndexToTipSide[dischargeNode.index]
491 if tipSide ~= nil then
492 local fillUnitIndex = dischargeNode.fillUnitIndex
493 if not tipSide.canTipIfEmpty and self:getFillUnitFillLevel(fillUnitIndex) == 0 then
494 canTip = false
495 end
496 end
497 end
498
499 return canTip
500end

getCanTogglePreferdTipSide

Description
Definition
getCanTogglePreferdTipSide()
Code
252function Trailer:getCanTogglePreferdTipSide()
253 local spec = self.spec_trailer
254 return spec.tipState == Trailer.TIPSTATE_CLOSED and spec.tipSideCount > 0
255end

getDischargeNodeEmptyFactor

Description
Definition
getDischargeNodeEmptyFactor()
Code
363function Trailer:getDischargeNodeEmptyFactor(superFunc, dischargeNode)
364 local spec = self.spec_trailer
365 local tipSide = spec.dischargeNodeIndexToTipSide[dischargeNode.index]
366
367 if tipSide ~= nil then
368 if tipSide.animation.name ~= nil and tipSide.animation.startTipTime ~= 0 then
369 -- log(self:getAnimationTime(tipSide.animation.name), tipSide.animation.startTipTime )
370 if self:getAnimationTime(tipSide.animation.name) < tipSide.animation.startTipTime then
371 return 0
372 end
373 end
374
375 if tipSide.doorAnimation.name ~= nil and tipSide.doorAnimation.startTipTime ~= 0 then
376 if self:getAnimationTime(tipSide.doorAnimation.name) < tipSide.doorAnimation.startTipTime then
377 return 0
378 end
379 end
380
381 return tipSide.currentEmptyFactor
382 end
383
384 return superFunc(self, dischargeNode)
385end

getIsNextCoverStateAllowed

Description
Definition
getIsNextCoverStateAllowed()
Code
504function Trailer:getIsNextCoverStateAllowed(superFunc, nextState)
505 local spec = self.spec_trailer
506
507 if spec.currentTipSideIndex ~= nil then
508 local tipSide = spec.tipSides[spec.currentTipSideIndex]
509 local dischargeNode = self:getDischargeNodeByIndex(tipSide.dischargeNodeIndex)
510
511 local cover = self:getCoverByFillUnitIndex(dischargeNode.fillUnitIndex)
512 if cover ~= nil then
513 if nextState ~= cover.index then
514 return false
515 end
516 end
517 end
518
519 return superFunc(self, nextState)
520end

getTipState

Description
Definition
getTipState()
Code
357function Trailer:getTipState()
358 return self.spec_trailer.tipState
359end

initializeAnimationPart

Description
Definition
initializeAnimationPart()
Code
407function Trailer:initializeAnimationPart(superFunc, animation, part, i, numParts)
408
409 superFunc(self, animation, part, i, numParts)
410
411 -- find the next tipSideEmptyFactor part
412 if part.endTipSideEmptyFactor ~= nil then
413 for j=i+1, numParts do
414 local part2 = animation.parts[j]
415 if part.node == part2.node and part2.endTipSideEmptyFactor ~= nil then
416 if part.startTime + part.duration > part2.startTime+0.001 then
417 g_logManager:xmlWarning(self.configFileName, "Overlapping tipSideEmptyFactor parts for node '%s' in animation '%s'", getName(part.node), animation.name)
418 end
419 part.nextTipSideEmptyFactorPart = part2
420 part2.prevTipSideEmptyFactorPart = part
421 if part2.startTipSideEmptyFactor == nil then
422 part2.startTipSideEmptyFactor = {part.endTipSideEmptyFactor[1], part.endTipSideEmptyFactor[2], part.endTipSideEmptyFactor[3]}
423 end
424 break
425 end
426 end
427 end
428end

initSpecialization

Description
Definition
initSpecialization()
Code
78function Trailer.initSpecialization()
79 g_configurationManager:addConfigurationType("trailer", g_i18n:getText("configuration_trailer"), "trailer", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
80end

loadAnimationPart

Description
Definition
loadAnimationPart()
Code
389function Trailer:loadAnimationPart(superFunc, xmlFile, partKey, part)
390 if not superFunc(self, xmlFile, partKey, part) then
391 return false
392 end
393
394 local startTipSideEmptyFactor = getXMLFloat(xmlFile, partKey.."#startTipSideEmptyFactor")
395 local endTipSideEmptyFactor = getXMLFloat(xmlFile, partKey.."#endTipSideEmptyFactor")
396
397 if startTipSideEmptyFactor ~= nil and endTipSideEmptyFactor ~= nil then
398 part.startTipSideEmptyFactor = startTipSideEmptyFactor
399 part.endTipSideEmptyFactor = endTipSideEmptyFactor
400 end
401
402 return true
403end

loadTipSide

Description
Definition
loadTipSide()
Code
205function Trailer:loadTipSide(xmlFile, key, entry)
206 local name = getXMLString(xmlFile, key .. "#name")
207 entry.name = g_i18n:convertText(name, self.customEnvironment)
208 if entry.name == nil then
209 g_logManager:xmlWarning(self.configFileName, "Given tipSide name '%s' not found for '%s'!", tostring(name), key)
210 return false
211 end
212
213 entry.dischargeNodeIndex = Utils.getNoNil(getXMLInt(xmlFile, key .. "#dischargeNodeIndex"), 1)
214 entry.canTipIfEmpty = Utils.getNoNil(getXMLBool(xmlFile, key .. "#canTipIfEmpty"), true)
215
216 entry.animation = {}
217 entry.animation.name = getXMLString(xmlFile, key .. ".animation#name")
218 if entry.animation.name == nil then
219 g_logManager:xmlWarning(self.configFileName, "Missing animation name for '%s'!", key)
220 return false
221 end
222 entry.animation.speedScale = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".animation#speedScale"), 1.0)
223 entry.animation.startTipTime = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".animation#startTipTime"), 0)
224
225 entry.doorAnimation = {}
226 entry.doorAnimation.name = getXMLString(xmlFile, key .. ".doorAnimation#name")
227 entry.doorAnimation.speedScale = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".doorAnimation#speedScale"), 1.0)
228 entry.doorAnimation.startTipTime = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".doorAnimation#startTipTime"), 0)
229 entry.doorAnimation.delayedClosing = Utils.getNoNil(getXMLBool(xmlFile, key .. ".doorAnimation#delayedClosing"), false)
230
231 if self.isClient then
232 entry.animationNodes = g_animationManager:loadAnimations(self.xmlFile, key..".animationNodes", self.components, self, self.i3dMappings)
233 end
234
235 entry.currentEmptyFactor = 1
236
237 return true
238end

onDelete

Description
Definition
onDelete()
Code
131function Trailer:onDelete()
132 if self.isClient then
133 local spec = self.spec_trailer
134 for _, tipSide in ipairs(spec.tipSides) do
135 g_animationManager:deleteAnimations(tipSide.animationNodes)
136 end
137 end
138end

onDischargeStateChanged

Description
Definition
onDischargeStateChanged()
Code
548function Trailer:onDischargeStateChanged(dischargState)
549 local spec = self.spec_trailer
550
551 if dischargState == Dischargeable.DISCHARGE_STATE_OFF then
552 self:stopTipping()
553 elseif dischargState == Dischargeable.DISCHARGE_STATE_GROUND or dischargState == Dischargeable.DISCHARGE_STATE_OBJECT then
554 self:startTipping(spec.preferedTipSideIndex, false)
555 end
556end

onLoad

Description
Definition
onLoad()
Code
84function Trailer:onLoad(savegame)
85 local spec = self.spec_trailer
86
87 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.tipScrollerNodes.tipScrollerNode", "vehicle.trailer.trailerConfigurations.trailerConfiguration.trailer.tipSide.animationNodes.animationNode") --FS17 to FS19
88 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.tipRotationNodes.tipRotationNode", "vehicle.trailer.trailerConfigurations.trailerConfiguration.trailer.tipSide.animationNodes.animationNode") --FS17 to FS19
89 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.tipAnimations.tipAnimation", "vehicle.trailer.trailerConfigurations.trailerConfiguration.trailer.tipSide") --FS17 to FS19
90
91
92 local trailerConfigurationId = Utils.getNoNil(self.configurations["trailer"], 1)
93 local configKey = string.format("vehicle.trailer.trailerConfigurations.trailerConfiguration(%d).trailer", trailerConfigurationId -1)
94 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.trailer.trailerConfigurations.trailerConfiguration", trailerConfigurationId , self.components, self)
95
96 spec.tipSides = {}
97 spec.dischargeNodeIndexToTipSide = {}
98 local i = 0
99 while true do
100 local key = string.format("%s.tipSide(%d)", configKey, i)
101 if not hasXMLProperty(self.xmlFile, key) then
102 break
103 end
104
105 local entry = {}
106 if self:loadTipSide(self.xmlFile, key, entry) then
107 table.insert(spec.tipSides, entry)
108 spec.dischargeNodeIndexToTipSide[entry.dischargeNodeIndex] = entry
109 end
110 i = i + 1
111 end
112
113 spec.tipSideCount = table.getn(spec.tipSides)
114 spec.preferedTipSideIndex = 1
115 spec.currentTipSideIndex = nil
116
117 spec.tipState = Trailer.TIPSTATE_CLOSED
118
119 spec.remainingFillDelta = 0
120
121 if spec.tipSideCount > 1 and savegame ~= nil then
122 local tipSideIndex = getXMLInt(savegame.xmlFile, savegame.key..".trailer#tipSideIndex")
123 if tipSideIndex ~= nil then
124 self:setPreferedTipSide(tipSideIndex, true)
125 end
126 end
127end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
144function Trailer:onReadStream(streamId, connection)
145 local spec = self.spec_trailer
146
147 if spec.tipSideCount > 1 then
148 self:setPreferedTipSide(streamReadUIntN(streamId, Trailer.TIP_SIDE_NUM_BITS), true)
149 end
150end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
530function Trailer:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
531 if self.isClient then
532 local spec = self.spec_trailer
533 if spec.tipSideCount < 2 then
534 return
535 end
536
537 self:clearActionEventsTable(spec.actionEvents)
538
539 if isActiveForInputIgnoreSelection then
540 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_TIPSIDE, self, Trailer.actionEventToggleTipSide, false, true, false, true, nil)
541 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
542 end
543 end
544end

onUpdate

Description
Definition
onUpdate()
Code
166function Trailer:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
167 local spec = self.spec_trailer
168
169 if spec.tipSideCount > 1 then
170 local actionEvent = spec.actionEvents[InputAction.TOGGLE_TIPSIDE]
171 if actionEvent ~= nil then
172 local state = self:getCanTogglePreferdTipSide()
173 g_inputBinding:setActionEventActive(actionEvent.actionEventId, state)
174
175 if state then
176 local text = string.format( g_i18n:getText("action_toggleTipSide"), spec.tipSides[spec.preferedTipSideIndex].name )
177 g_inputBinding:setActionEventText(actionEvent.actionEventId, text)
178 end
179 end
180 end
181
182 -- update tipState
183 if spec.tipState == Trailer.TIPSTATE_OPENING then
184 local tipSide = spec.tipSides[spec.currentTipSideIndex]
185 if tipSide ~= nil then
186 local animTime = self:getAnimationTime(tipSide.animation.name)
187 if animTime >= 1.0 then
188 spec.tipState = Trailer.TIPSTATE_OPEN
189 end
190 end
191 elseif spec.tipState == Trailer.TIPSTATE_CLOSING then
192 local tipSide = spec.tipSides[spec.currentTipSideIndex]
193 if tipSide ~= nil then
194 local animTime = self:getAnimationTime(tipSide.animation.name)
195 if animTime <= 0.0 then
196 spec.tipState = Trailer.TIPSTATE_CLOSED
197 self:endTipping()
198 end
199 end
200 end
201end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, integer connection)
Arguments
integerstreamIdstreamId
integerconnectionconnection
Code
156function Trailer:onWriteStream(streamId, connection)
157 local spec = self.spec_trailer
158
159 if spec.tipSideCount > 1 then
160 streamWriteUIntN(streamId, spec.preferedTipSideIndex, Trailer.TIP_SIDE_NUM_BITS)
161 end
162end

postInitializeAnimationPart

Description
Definition
postInitializeAnimationPart()
Code
432function Trailer:postInitializeAnimationPart(superFunc, animation, part, i, numParts)
433
434 superFunc(self, animation, part, i, numParts)
435
436 if part.endTipSideEmptyFactor ~= nil and part.startTipSideEmptyFactor == nil then
437 part.startTipSideEmptyFactor = 0
438 end
439end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
24function Trailer.prerequisitesPresent(specializations)
25 return SpecializationUtil.hasSpecialization(FillUnit, specializations) and
26 SpecializationUtil.hasSpecialization(Dischargeable, specializations) and
27 SpecializationUtil.hasSpecialization(AnimatedVehicle, specializations)
28end

registerEventListeners

Description
Definition
registerEventListeners()
Code
66function Trailer.registerEventListeners(vehicleType)
67 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Trailer)
68 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Trailer)
69 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Trailer)
70 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Trailer)
71 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Trailer)
72 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Trailer)
73 SpecializationUtil.registerEventListener(vehicleType, "onDischargeStateChanged", Trailer)
74end

registerEvents

Description
Definition
registerEvents()
Code
32function Trailer.registerEvents(vehicleType)
33 SpecializationUtil.registerEvent(vehicleType, "onStartTipping")
34 SpecializationUtil.registerEvent(vehicleType, "onStopTipping")
35 SpecializationUtil.registerEvent(vehicleType, "onEndTipping")
36end

registerFunctions

Description
Definition
registerFunctions()
Code
40function Trailer.registerFunctions(vehicleType)
41 SpecializationUtil.registerFunction(vehicleType, "loadTipSide", Trailer.loadTipSide)
42 SpecializationUtil.registerFunction(vehicleType, "getCanTogglePreferdTipSide", Trailer.getCanTogglePreferdTipSide)
43 SpecializationUtil.registerFunction(vehicleType, "setPreferedTipSide", Trailer.setPreferedTipSide)
44 SpecializationUtil.registerFunction(vehicleType, "startTipping", Trailer.startTipping)
45 SpecializationUtil.registerFunction(vehicleType, "stopTipping", Trailer.stopTipping)
46 SpecializationUtil.registerFunction(vehicleType, "endTipping", Trailer.endTipping)
47 SpecializationUtil.registerFunction(vehicleType, "getTipState", Trailer.getTipState)
48end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
52function Trailer.registerOverwrittenFunctions(vehicleType)
53 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDischargeNodeEmptyFactor", Trailer.getDischargeNodeEmptyFactor)
54 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadAnimationPart", Trailer.loadAnimationPart)
55 SpecializationUtil.registerOverwrittenFunction(vehicleType, "initializeAnimationPart", Trailer.initializeAnimationPart)
56 SpecializationUtil.registerOverwrittenFunction(vehicleType, "postInitializeAnimationPart", Trailer.postInitializeAnimationPart)
57 SpecializationUtil.registerOverwrittenFunction(vehicleType, "updateAnimationPart", Trailer.updateAnimationPart)
58 SpecializationUtil.registerOverwrittenFunction(vehicleType, "resetAnimationPartValues", Trailer.resetAnimationPartValues)
59 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanDischargeToGround", Trailer.getCanDischargeToGround)
60 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsNextCoverStateAllowed", Trailer.getIsNextCoverStateAllowed)
61 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", Trailer.getCanBeSelected)
62end

resetAnimationPartValues

Description
Definition
resetAnimationPartValues()
Code
479function Trailer:resetAnimationPartValues(superFunc, part)
480 superFunc(self, part)
481 part.tipSide = nil
482end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
242function Trailer:saveToXMLFile(xmlFile, key, usedModNames)
243 local spec = self.spec_trailer
244
245 if spec.tipSideCount > 1 then
246 setXMLInt(xmlFile, key.."#tipSideIndex", spec.preferedTipSideIndex)
247 end
248end

setPreferedTipSide

Description
Definition
setPreferedTipSide()
Code
259function Trailer:setPreferedTipSide(index, noEventSend)
260 local spec = self.spec_trailer
261 index = math.max(1, math.min(spec.tipSideCount, index))
262
263 if index ~= spec.preferedTipSideIndex then
264 if spec.tipSideCount > 1 then
265 if noEventSend == nil or noEventSend == false then
266 if g_server ~= nil then
267 g_server:broadcastEvent(TrailerToggleTipSideEvent:new(self, index), nil, nil, self)
268 else
269 g_client:getServerConnection():sendEvent(TrailerToggleTipSideEvent:new(self, index))
270 end
271 end
272 end
273 end
274
275 spec.preferedTipSideIndex = index
276 local tipSide = spec.tipSides[index]
277 self:setCurrentDischargeNodeIndex(tipSide.dischargeNodeIndex)
278end

startTipping

Description
Definition
startTipping()
Code
282function Trailer:startTipping(tipSideIndex, noEventSend)
283 local spec = self.spec_trailer
284 local tipSide = spec.tipSides[tipSideIndex]
285 if tipSide ~= nil then
286 local animTime = self:getAnimationTime(tipSide.animation.name)
287
288 self:playAnimation(tipSide.animation.name, tipSide.animation.speedScale, animTime, true)
289
290 if tipSide.doorAnimation.name ~= nil then
291 local animTime = self:getAnimationTime(tipSide.doorAnimation.name)
292 self:playAnimation(tipSide.doorAnimation.name, tipSide.doorAnimation.speedScale, animTime, true)
293 end
294
295 g_animationManager:startAnimations(tipSide.animationNodes)
296
297 spec.tipState = Trailer.TIPSTATE_OPENING
298 spec.currentTipSideIndex = tipSideIndex
299
300 self:setCurrentDischargeNodeIndex(tipSide.dischargeNodeIndex)
301
302 spec.remainingFillDelta = 0
303
304 SpecializationUtil.raiseEvent(self, "onStartTipping", tipSideIndex)
305 end
306end

stopTipping

Description
Definition
stopTipping()
Code
310function Trailer:stopTipping(noEventSend)
311 local spec = self.spec_trailer
312 local tipSide = spec.tipSides[spec.currentTipSideIndex]
313 if tipSide ~= nil then
314 local animTime = self:getAnimationTime(tipSide.animation.name)
315 self:playAnimation(tipSide.animation.name, -tipSide.animation.speedScale, animTime, true)
316
317 if tipSide.doorAnimation.name ~= nil then
318 if not tipSide.doorAnimation.delayedClosing then
319 local animTime = self:getAnimationTime(tipSide.doorAnimation.name)
320 self:playAnimation(tipSide.doorAnimation.name, -tipSide.doorAnimation.speedScale, animTime, true)
321 end
322 end
323
324 g_animationManager:stopAnimations(tipSide.animationNodes)
325
326 spec.tipState = Trailer.TIPSTATE_CLOSING
327
328 spec.remainingFillDelta = 0
329
330 SpecializationUtil.raiseEvent(self, "onStopTipping")
331 end
332end

updateAnimationPart

Description
Definition
updateAnimationPart()
Code
443function Trailer:updateAnimationPart(superFunc, animation, part, durationToEnd, dtToUse, realDt)
444 local spec = self.spec_trailer
445
446 local hasPartChanged = superFunc(self, animation, part, durationToEnd, dtToUse, realDt)
447
448 if part.startTipSideEmptyFactor ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextTipSideEmptyFactorPart, part.prevTipSideEmptyFactorPart, animation, true)) then
449 local destFactor = part.endTipSideEmptyFactor
450 if animation.currentSpeed < 0 then
451 destFactor = part.startTipSideEmptyFactor
452 end
453 if part.tipSide == nil then
454 local dischargeNode = self:getDischargeNodeByNode(part.node)
455 local tipSide = spec.dischargeNodeIndexToTipSide[dischargeNode.index]
456 if tipSide == nil then
457 g_logManager:xmlWarning(self.configFileName, "Could not update discharge emptyFactor. No tipSide defined for node '%s'!", getName(part.node))
458 part.startTipSideEmptyFactor = nil
459 return hasPartChanged
460 end
461
462 part.tipSide = tipSide
463 local invDuration = 1.0/math.max(durationToEnd, 0.001)
464 part.speedEmptyFactor = (destFactor-tipSide.currentEmptyFactor)*invDuration
465 end
466
467 local newValue = AnimatedVehicle.getMovedLimitedValue(part.tipSide.currentEmptyFactor, destFactor, part.speedEmptyFactor, dtToUse)
468 if newValue then
469 part.tipSide.currentEmptyFactor = newValue
470 hasPartChanged = true
471 end
472 end
473
474 return hasPartChanged
475end