LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

Pipe

Description
Specialization for vehicles unloading via (foldable) pipe/conveyor (combine, augar wagon, potato/sugarBeet harvester, ...)
Functions

actionEventToggleDischargeToGround

Description
Definition
actionEventToggleDischargeToGround()
Code
1379function Pipe.actionEventToggleDischargeToGround(self, actionName, inputValue, callbackState, isAnalog)
1380 self:setPipeDischargeToGround()
1381end

actionEventTogglePipe

Description
Definition
actionEventTogglePipe()
Code
1363function Pipe.actionEventTogglePipe(self, actionName, inputValue, callbackState, isAnalog)
1364 local spec = self.spec_pipe
1365 local nextState = spec.targetState + 1
1366 if nextState > spec.numStates then
1367 nextState = 1
1368 end
1369 if self:getIsPipeStateChangeAllowed(nextState) then
1370 self:setPipeState(nextState)
1371 elseif nextState ~= 1 and self:getIsPipeStateChangeAllowed(1) then
1372 -- also try to close the pipe if other states are not allowed
1373 self:setPipeState(1)
1374 end
1375end

dischargeToGround

Description
Definition
dischargeToGround()
Code
1125function Pipe:dischargeToGround(superFunc, dischargeNode, emptyLiters)
1126 local spec = self.spec_pipe
1127 if spec.toggleableDischargeToGround and not spec.dischargeToGroundState then
1128 local unloadInfo = self:getFillVolumeUnloadInfo(dischargeNode.unloadInfoIndex)
1129 self:addFillUnitFillLevel(self:getOwnerFarmId(), dischargeNode.fillUnitIndex, -emptyLiters, self:getFillUnitFillType(dischargeNode.fillUnitIndex), ToolType.UNDEFINED, unloadInfo)
1130
1131 return -emptyLiters, emptyLiters > 0, emptyLiters > 0
1132 end
1133
1134 return superFunc(self, dischargeNode, emptyLiters)
1135end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
1266function Pipe:getCanBeSelected(superFunc)
1267 return true
1268end

getCanBeTurnedOn

Description
Definition
getCanBeTurnedOn()
Code
1021function Pipe:getCanBeTurnedOn(superFunc)
1022 local spec = self.spec_pipe
1023
1024 if spec.hasMovablePipe then
1025 if next(spec.turnOnAllowedStates) ~= nil then
1026 local isAllowed = false
1027 for pipeState,_ in pairs(spec.turnOnAllowedStates) do
1028 if pipeState == spec.currentState then
1029 isAllowed = true
1030 break
1031 end
1032 end
1033 if not isAllowed then
1034 return false
1035 end
1036 end
1037 end
1038
1039 return superFunc(self)
1040end

getCanToggleDischargeToGround

Description
Definition
getCanToggleDischargeToGround()
Code
1150function Pipe:getCanToggleDischargeToGround(superFunc)
1151 local spec = self.spec_pipe
1152 if spec.automaticDischarge and spec.toggleableDischargeToGround then
1153 return false
1154 end
1155
1156 return superFunc(self)
1157end

getCanToggleDischargeToObject

Description
Definition
getCanToggleDischargeToObject()
Code
1139function Pipe:getCanToggleDischargeToObject(superFunc)
1140 local spec = self.spec_pipe
1141 if spec.automaticDischarge then
1142 return false
1143 end
1144
1145 return superFunc(self)
1146end

getIsAIPreparingToDrive

Description
Definition
getIsAIPreparingToDrive()
Code
1285function Pipe:getIsAIPreparingToDrive(superFunc)
1286 local spec = self.spec_pipe
1287 if spec.hasMovablePipe then
1288 if spec.currentState ~= spec.targetState then
1289 return true
1290 end
1291 end
1292
1293 return superFunc(self)
1294end

getIsAIReadyToDrive

Description
Definition
getIsAIReadyToDrive()
Code
1272function Pipe:getIsAIReadyToDrive(superFunc)
1273 local spec = self.spec_pipe
1274 if spec.hasMovablePipe then
1275 if spec.currentState ~= 1 then
1276 return false
1277 end
1278 end
1279
1280 return superFunc(self)
1281end

getIsDischargeNodeActive

Description
Definition
getIsDischargeNodeActive()
Code
1009function Pipe:getIsDischargeNodeActive(superFunc, dischargeNode)
1010 local spec = self.spec_pipe
1011 if dischargeNode.index == self:getPipeDischargeNodeIndex() then
1012 -- do an explicit true check to avoid nil issues
1013 return spec.unloadingStates[spec.currentState] == true
1014 end
1015
1016 return superFunc(self, dischargeNode)
1017end

getIsFoldAllowed

Description
Definition
getIsFoldAllowed()
Code
1067function Pipe:getIsFoldAllowed(superFunc, direction, onAiTurnOn)
1068 local spec = self.spec_pipe
1069
1070 if spec.hasMovablePipe then
1071 if spec.currentState > spec.foldMaxState or spec.currentState < spec.foldMinState then
1072 return false, spec.texts.warningFoldingPipe
1073 end
1074 end
1075
1076 return superFunc(self, direction, onAiTurnOn)
1077end

getIsMovingToolActive

Description
Definition
getIsMovingToolActive()
Code
1173function Pipe:getIsMovingToolActive(superFunc, movingTool)
1174 local spec = self.spec_pipe
1175 if movingTool.freezingPipeStates ~= nil then
1176 for _, state in pairs(movingTool.freezingPipeStates) do
1177 if spec.currentState == state or spec.targetState == state or spec.currentState == 0 then
1178 return false
1179 end
1180 end
1181 end
1182
1183 return superFunc(self, movingTool)
1184end

getIsNextCoverStateAllowed

Description
Definition
getIsNextCoverStateAllowed()
Code
1197function Pipe:getIsNextCoverStateAllowed(superFunc, nextState)
1198 if not superFunc(self, nextState) then
1199 return false
1200 end
1201
1202 local spec = self.spec_pipe
1203 local cover = self.spec_cover.covers[nextState]
1204 if nextState ~= 0 then
1205 if spec.currentState < cover.minPipeState or spec.currentState > cover.maxPipeState then
1206 return false
1207 end
1208 end
1209
1210 return true
1211end

getIsPipeStateChangeAllowed

Description
Definition
getIsPipeStateChangeAllowed()
Code
596function Pipe:getIsPipeStateChangeAllowed(pipeState)
597 local spec = self.spec_pipe
598
599 local foldAnimTime
600 if self.getFoldAnimTime ~= nil then
601 foldAnimTime = self:getFoldAnimTime()
602 end
603
604 if foldAnimTime ~= nil and (foldAnimTime < spec.foldMinTime or foldAnimTime > spec.foldMaxTime) then
605 return false
606 end
607
608 return true
609end

getPipeDischargeNodeIndex

Description
Definition
getPipeDischargeNodeIndex()
Code
1230function Pipe:getPipeDischargeNodeIndex(state)
1231 local spec = self.spec_pipe
1232
1233 if state == nil then
1234 state = spec.currentState
1235 end
1236
1237 if spec.dischargeNodeMapping[state] ~= nil then
1238 return spec.dischargeNodeMapping[state]
1239 end
1240
1241 return spec.dischargeNodeIndex
1242end

getTurnedOnNotAllowedWarning

Description
Definition
getTurnedOnNotAllowedWarning()
Code
1044function Pipe:getTurnedOnNotAllowedWarning(superFunc)
1045 local spec = self.spec_pipe
1046
1047 if spec.hasMovablePipe then
1048 if next(spec.turnOnAllowedStates) ~= nil then
1049 local isAllowed = false
1050 for pipeState,_ in pairs(spec.turnOnAllowedStates) do
1051 if pipeState == spec.currentState then
1052 isAllowed = true
1053 break
1054 end
1055 end
1056 if not isAllowed then
1057 return spec.turnOnStateWarning
1058 end
1059 end
1060 end
1061
1062 return superFunc(self)
1063end

handleDischarge

Description
Definition
handleDischarge()
Code
1081function Pipe:handleDischarge(superFunc, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel)
1082 local spec = self.spec_pipe
1083 if spec.automaticDischarge then
1084 -- do nothing if it is pipe dischargenode
1085 if dischargeNode.index ~= self:getPipeDischargeNodeIndex() then
1086 superFunc(self, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel)
1087 end
1088 else
1089 superFunc(self, dischargeNode, dischargedLiters, minDropReached, hasMinDropFillLevel)
1090 end
1091end

handleDischargeRaycast

Description
Definition
handleDischargeRaycast()
Code
1095function Pipe:handleDischargeRaycast(superFunc, dischargeNode, hitObject, hitShape, hitDistance, hitFillUnitIndex, hitTerrain)
1096 local spec = self.spec_pipe
1097 if spec.automaticDischarge then
1098 local stopDischarge = false
1099 if self:getIsPowered() and hitObject ~= nil then
1100 local fillType = self:getDischargeFillType(dischargeNode)
1101 local allowFillType = hitObject:getFillUnitAllowsFillType(hitFillUnitIndex, fillType)
1102 if allowFillType and hitObject:getFillUnitFreeCapacity(hitFillUnitIndex, fillType, self:getOwnerFarmId()) > 0 then
1103 self:setDischargeState(Dischargeable.DISCHARGE_STATE_OBJECT, true)
1104 else
1105 stopDischarge = true
1106 end
1107 elseif self:getIsPowered() and spec.toggleableDischargeToGround then
1108 self:setDischargeState(Dischargeable.DISCHARGE_STATE_GROUND, true)
1109 else
1110 stopDischarge = true
1111 end
1112
1113 if stopDischarge and self:getDischargeState() == Dischargeable.DISCHARGE_STATE_OBJECT then
1114 self:setDischargeState(Dischargeable.DISCHARGE_STATE_OFF, true)
1115 end
1116
1117 return
1118 end
1119
1120 superFunc(self, dischargeNode, hitObject, hitShape, hitDistance, hitFillUnitIndex, hitTerrain)
1121end

initSpecialization

Description
Called on specialization initializing
Definition
initSpecialization()
Code
24function Pipe.initSpecialization()
25 g_configurationManager:addConfigurationType("pipe", g_i18n:getText("configuration_pipe"), "pipe", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
26
27 local schema = Vehicle.xmlSchema
28 schema:setXMLSpecializationType("Pipe")
29
30 AnimationManager.registerAnimationNodesXMLPaths(schema, "vehicle.pipe.animationNodes")
31
32 schema:register(XMLValueType.VECTOR_N, Cylindered.MOVING_TOOL_XML_KEY .. "#freezingPipeStates", "Freezing pipe states")
33
34 schema:register(XMLValueType.INT, Cover.COVER_XML_KEY .. "#minPipeState", "Min. pipe state", 0)
35 schema:register(XMLValueType.INT, Cover.COVER_XML_KEY .. "#maxPipeState", "Max. pipe state", "inf.")
36
37 Pipe.registers(schema, "vehicle.pipe")
38 Pipe.registers(schema, "vehicle.pipe.pipeConfigurations.pipeConfiguration(?)")
39 ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.pipe.pipeConfigurations.pipeConfiguration(?)")
40
41 schema:setXMLSpecializationType()
42
43 local schemaSavegame = Vehicle.xmlSchemaSavegame
44 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).pipe#state", "Current pipe state")
45end

loadCoverFromXML

Description
Definition
loadCoverFromXML()
Code
1188function Pipe:loadCoverFromXML(superFunc, xmlFile, key, cover)
1189 cover.minPipeState = xmlFile:getValue(key.."#minPipeState", 0)
1190 cover.maxPipeState = xmlFile:getValue(key.."#maxPipeState", math.huge)
1191
1192 return superFunc(self, xmlFile, key, cover)
1193end

loadMovingToolFromXML

Description
Definition
loadMovingToolFromXML()
Code
1161function Pipe:loadMovingToolFromXML(superFunc, xmlFile, key, entry)
1162 if not superFunc(self, xmlFile, key, entry) then
1163 return false
1164 end
1165
1166 entry.freezingPipeStates = xmlFile:getValue(key.."#freezingPipeStates", nil, true)
1167
1168 return true
1169end

loadPipeNodes

Description
Definition
loadPipeNodes()
Code
469function Pipe:loadPipeNodes(pipeNodes, xmlFile, baseKey)
470 local spec = self.spec_pipe
471
472 local maxPriority = 0
473 local i = 0
474 while true do
475 local key = string.format("%s(%d)", baseKey, i)
476 if not xmlFile:hasProperty(key) then
477 break
478 end
479 local node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings)
480 if node ~= nil then
481 local entry = {}
482 entry.node = node
483 entry.autoAimXRotation = xmlFile:getValue(key.."#autoAimXRotation", false)
484 entry.autoAimYRotation = xmlFile:getValue(key.."#autoAimYRotation", false)
485 entry.autoAimInvertZ = xmlFile:getValue(key.."#autoAimInvertZ", false)
486 entry.states = {}
487
488 entry.subPipeNode = xmlFile:getValue(key.."#subPipeNode", nil, self.components, self.i3dMappings)
489 if entry.subPipeNode ~= nil then
490 local x1, _, _ = getRotation(entry.node)
491 local x2, _, _ = localRotationToLocal(entry.subPipeNode, getParent(entry.node), 0, 0, 0)
492 entry.subPipeNodeRatio = xmlFile:getValue(key.."#subPipeNodeRatio", math.abs(x1 / x2))
493 end
494
495 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key .. ".state1", key .. ".state") -- FS19 to FS21
496
497 for state=1, spec.numStates do
498 local stateKey = key..string.format(".state(%d)", state - 1)
499 entry.states[state] = {}
500
501 local x, y, z = xmlFile:getValue(stateKey.."#translation", {getTranslation(node)})
502 if state == 1 then
503 setTranslation(node, x, y, z)
504 end
505 entry.states[state].translation = {x, y, z}
506
507 x, y, z = xmlFile:getValue(stateKey.."#rotation", {getRotation(node)})
508 if state == 1 then
509 setRotation(node, x, y, z)
510 end
511 entry.states[state].rotation = {x, y, z}
512 end
513
514 local x, y, z = xmlFile:getValue(key.."#translationSpeeds")
515 if x ~= nil and y ~= nil and z ~= nil then
516 x, y, z = x * 0.001, y * 0.001, z * 0.001
517 if x ~= 0 or y ~= 0 or z ~= 0 then
518 entry.translationSpeeds = {x, y, z}
519 end
520 end
521 x, y, z = xmlFile:getValue(key.."#rotationSpeeds")
522 if x ~= nil and y ~= nil and z ~= nil then
523 x, y, z = x * 0.001, y * 0.001, z *0.001
524 if x ~= 0 or y ~= 0 or z ~= 0 then
525 entry.rotationSpeeds = {x, y, z}
526 end
527 end
528
529 x, y, z = string.getVector(xmlFile:getValue(key.."#minRotationLimits"))
530 if x ~= nil or y ~= nil or z ~= nil then
531 x = (x ~= nil and math.rad(x)) or nil
532 y = (y ~= nil and math.rad(y)) or nil
533 z = (z ~= nil and math.rad(z)) or nil
534 entry.minRotationLimits = {x, y, z}
535 end
536 x, y, z = string.getVector(xmlFile:getValue(key.."#maxRotationLimits"))
537 if x ~= nil or y ~= nil or z ~= nil then
538 x = (x ~= nil and math.rad(x)) or nil
539 y = (y ~= nil and math.rad(y)) or nil
540 z = (z ~= nil and math.rad(z)) or nil
541 entry.maxRotationLimits = {x, y, z}
542 end
543
544 entry.foldPriority = xmlFile:getValue(key.."#foldPriority", 0)
545 maxPriority = math.max(entry.foldPriority, maxPriority)
546
547 x, y, z = getTranslation(node)
548 entry.curTranslation = {x, y, z}
549
550 x, y, z = getRotation(node)
551 entry.curRotation = {x, y, z}
552 entry.lastTargetRotation = {x, y, z}
553
554 entry.bendingRegulation = xmlFile:getValue(key.."#bendingRegulation", 0)
555
556 entry.regulationNodes = {}
557
558 local j = 0
559 while true do
560 local regKey = string.format("%s.bendingRegulationNode(%d)", key, j)
561 if not xmlFile:hasProperty(regKey) then
562 break
563 end
564
565 local regulationNode = {}
566 regulationNode.node = xmlFile:getValue(regKey.."#node", nil, self.components, self.i3dMappings)
567 if regulationNode.node ~= nil then
568 regulationNode.startRotation = {getRotation(regulationNode.node)}
569
570 local axis = xmlFile:getValue(regKey.."#axis", 1)
571 local direction = xmlFile:getValue(regKey.."#direction", 1)
572
573 regulationNode.weights = {0, 0, 0}
574 regulationNode.weights[MathUtil.clamp(axis, 1, 3)] = direction
575
576 table.insert(entry.regulationNodes, regulationNode)
577 else
578 Logging.xmlWarning(self.xmlFile, "Failed to load bendingRegulationNode '%s'", regKey)
579 end
580
581 j = j + 1
582 end
583
584 table.insert(pipeNodes, entry)
585 end
586 i = i + 1
587 end
588
589 for _, pipeNode in ipairs(pipeNodes) do
590 pipeNode.inverseFoldPriority = maxPriority-pipeNode.foldPriority
591 end
592end

loadUnloadingTriggers

Description
Definition
loadUnloadingTriggers()
Code
445function Pipe:loadUnloadingTriggers(unloadingTriggers, xmlFile, baseKey)
446 local i = 0
447 while true do
448 local key = string.format("%s(%d)", baseKey, i)
449 if not xmlFile:hasProperty(key) then
450 break
451 end
452
453 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key.."#index", key.."#node") --FS17 to FS19
454
455 local node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings)
456 if node ~= nil then
457 if CollisionFlag.getHasFlagSet(node, CollisionFlag.FILLABLE) then
458 table.insert(unloadingTriggers, {node=node})
459 else
460 Logging.xmlWarning(self.xmlFile, "Missing collision mask bit '%d'. Please add this bit to unload trigger node '%s' in '%s'", CollisionFlag.getBit(CollisionFlag.FILLABLE), getName(node), key)
461 end
462 end
463 i = i + 1
464 end
465end

onAIImplementPrepare

Description
Definition
onAIImplementPrepare()
Code
1352function Pipe:onAIImplementPrepare()
1353 local spec = self.spec_pipe
1354 if spec.hasMovablePipe then
1355 if self:getIsPipeStateChangeAllowed(1) then
1356 self:setPipeState(1)
1357 end
1358 end
1359end

onDelete

Description
Definition
onDelete()
Code
314function Pipe:onDelete()
315 local spec = self.spec_pipe
316
317 if spec.unloadingTriggers ~= nil then
318 for _, unloadingTrigger in pairs(spec.unloadingTriggers) do
319 removeTrigger(unloadingTrigger.node)
320 end
321 end
322
323 g_animationManager:deleteAnimations(spec.animationNodes)
324end

onDeletePipeObject

Description
Definition
onDeletePipeObject()
Code
1215function Pipe:onDeletePipeObject(object)
1216 local spec = self.spec_pipe
1217 if spec.objectsInTriggers[object] ~= nil then
1218 spec.objectsInTriggers[object] = nil
1219 spec.numObjectsInTriggers = spec.numObjectsInTriggers - 1
1220 end
1221
1222 if spec.unloadTriggersInTriggers[object] ~= nil then
1223 spec.unloadTriggersInTriggers[object] = nil
1224 spec.numUnloadTriggersInTriggers = spec.numUnloadTriggersInTriggers - 1
1225 end
1226end

onDischargeStateChanged

Description
Called on discharge state change
Definition
onDischargeStateChanged()
Code
1331function Pipe:onDischargeStateChanged(state)
1332 if self.isClient then
1333 local spec = self.spec_pipe
1334 local dischargeNode = self:getCurrentDischargeNode()
1335 local dischargeNodeIndex = nil
1336 if dischargeNode ~= nil then
1337 dischargeNodeIndex = dischargeNode.index
1338 end
1339 if dischargeNodeIndex == self:getPipeDischargeNodeIndex() then
1340 if state == Dischargeable.DISCHARGE_STATE_OFF then
1341 g_animationManager:stopAnimations(spec.animationNodes)
1342 else
1343 g_animationManager:startAnimations(spec.animationNodes)
1344 g_animationManager:setFillType(spec.animationNodes, self:getFillUnitLastValidFillType(dischargeNode.fillUnitIndex))
1345 end
1346 end
1347 end
1348end

onLoad

Description
Definition
onLoad()
Code
158function Pipe:onLoad(savegame)
159 local spec = self.spec_pipe
160
161 local pipeConfigurationId = Utils.getNoNil(self.configurations["pipe"], 1)
162 local baseKey = string.format("vehicle.pipe.pipeConfigurations.pipeConfiguration(%d)", pipeConfigurationId -1)
163 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.pipe.pipeConfigurations.pipeConfiguration", pipeConfigurationId , self.components, self)
164
165 -- fallback key
166 if not self.xmlFile:hasProperty(baseKey) then
167 baseKey = "vehicle.pipe"
168 end
169
170 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipeEffect.effectNode", baseKey..".pipeEffect.effectNode") --FS17 to FS19
171 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.overloading.trailerTriggers.trailerTrigger(0)#index", baseKey..".unloadingTriggers.unloadingTrigger(0)#node") --FS17 to FS19
172 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#raycastNodeIndex", baseKey..".raycast#node") --FS17 to FS19
173 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#raycastDistance", baseKey..".raycast#maxDistance") --FS17 to FS19
174 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#effectExtraDistanceOnTrailer", baseKey..".raycast#extraDistance") --FS17 to FS19
175 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#animName", baseKey..".animation#name") --FS17 to FS19
176 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#animSpeedScale", baseKey..".animation#speedScale") --FS17 to FS19
177 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#animSpeedScale", baseKey..".animation#speedScale") --FS17 to FS19
178 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe.node#node", baseKey..".node#node") --FS17 to FS19
179 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#numStates", baseKey..".states#num") --FS17 to FS19
180 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#unloadingStates", baseKey..".states#unloading") --FS17 to FS19
181 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#autoAimingStates", baseKey..".states#autoAiming") --FS17 to FS19
182 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.pipe#turnOnAllowed", baseKey..".states#turnOnAllowed") --FS17 to FS19
183
184 spec.turnOnStateWarning = string.format(self.xmlFile:getValue(baseKey.."#turnOnStateWarning", "warning_firstSetPipeState", self.customEnvironment), self.typeDesc)
185
186 spec.dischargeNodeIndex = self.xmlFile:getValue(baseKey .. "#dischargeNodeIndex", 1)
187 spec.forceDischargeNodeIndex = self.xmlFile:getValue(baseKey .. "#forceDischargeNodeIndex", true)
188 if spec.forceDischargeNodeIndex then
189 self:setCurrentDischargeNodeIndex(spec.dischargeNodeIndex)
190 end
191
192 spec.automaticDischarge = self.xmlFile:getValue(baseKey .. "#automaticDischarge", true)
193 spec.toggleableDischargeToGround = self.xmlFile:getValue(baseKey .. "#toggleableDischargeToGround", false)
194 spec.dischargeToGroundState = false
195
196 spec.unloadingTriggers = {}
197 spec.objectsInTriggers = {}
198 spec.unloadTriggersInTriggers = {}
199 spec.numObjectsInTriggers = 0
200 spec.numUnloadTriggersInTriggers = 0
201 spec.nearestObjectInTriggers = {objectId=nil, fillUnitIndex=0}
202 spec.nearestObjectInTriggersSent = {objectId=nil, fillUnitIndex=0}
203
204 self:loadUnloadingTriggers(spec.unloadingTriggers, self.xmlFile, baseKey .. ".unloadingTriggers.unloadingTrigger")
205 if #spec.unloadingTriggers == 0 then
206 Logging.xmlWarning(self.xmlFile, "No 'unloadingTriggers' defined for pipe 'vehicle.pipe'!")
207 else
208 for _,trigger in pairs(spec.unloadingTriggers) do
209 addTrigger(trigger.node, "unloadingTriggerCallback", self)
210 end
211 end
212
213 spec.animation = {}
214 spec.animation.name = self.xmlFile:getValue(baseKey .. ".animation#name")
215 spec.animation.speedScale = self.xmlFile:getValue(baseKey .. ".animation#speedScale", 1)
216
217 spec.currentState = 1
218 spec.targetState = 1
219 spec.numStates = self.xmlFile:getValue(baseKey .. ".states#num", 0)
220
221 spec.nodes = {}
222 self:loadPipeNodes(spec.nodes, self.xmlFile, baseKey .. ".pipeNodes.pipeNode")
223 spec.hasMovablePipe = #spec.nodes > 0 or spec.animation.name ~= nil
224
225 local function loadState(target, xmlFile, key)
226 local i = 0
227 local states = xmlFile:getValue(key, nil, true)
228 if states ~= nil then
229 for _, state in ipairs(states) do
230 target[state] = true
231 i = i + 1
232 end
233 end
234
235 return i
236 end
237
238 spec.unloadingStates = {}
239 spec.autoAimingStates = {}
240 spec.turnOnAllowedStates = {}
241 spec.numUnloadingStates = loadState(spec.unloadingStates, self.xmlFile, baseKey .. ".states#unloading")
242 spec.numAutoAimingStates = loadState(spec.autoAimingStates, self.xmlFile, baseKey .. ".states#autoAiming")
243 spec.numTurnOnAllowedStates = loadState(spec.turnOnAllowedStates, self.xmlFile, baseKey .. ".states#turnOnAllowed")
244
245 spec.dischargeNodeMapping = {}
246 local i = 0
247 while true do
248 local stateKey = string.format("%s.states.state(%d)", baseKey, i)
249 if not self.xmlFile:hasProperty(stateKey) then
250 break
251 end
252
253 local stateIndex = self.xmlFile:getValue(stateKey .. "#stateIndex")
254 local dischargeNodeIndex = self.xmlFile:getValue(stateKey .. "#dischargeNodeIndex")
255
256 if stateIndex ~= nil and dischargeNodeIndex ~= nil then
257 spec.dischargeNodeMapping[stateIndex] = dischargeNodeIndex
258 end
259
260 i = i + 1
261 end
262
263 if self.isClient then
264 spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, "vehicle.pipe.animationNodes", self.components, self, self.i3dMappings)
265 end
266
267 spec.foldMinTime = self.xmlFile:getValue(baseKey .. "#foldMinLimit", 0.0)
268 spec.foldMaxTime = self.xmlFile:getValue(baseKey .. "#foldMaxLimit", 1.0)
269 spec.foldMinState = self.xmlFile:getValue(baseKey .. "#foldMinState", 1)
270 spec.foldMaxState = self.xmlFile:getValue(baseKey .. "#foldMaxState", spec.numStates)
271
272 spec.aiFoldedPipeUsesTrailerSpace = self.xmlFile:getValue(baseKey .. "#aiFoldedPipeUsesTrailerSpace", false)
273
274 spec.texts = {}
275 spec.texts.warningFoldingPipe = g_i18n:getText("warning_foldingNotWhilePipeExtended")
276 spec.texts.pipeIn = g_i18n:getText("action_pipeIn")
277 spec.texts.pipeOut = g_i18n:getText("action_pipeOut")
278 spec.texts.startTipToGround = g_i18n:getText("action_startTipToGround")
279 spec.texts.stopTipToGround = g_i18n:getText("action_stopTipToGround")
280
281 spec.dirtyFlag = self:getNextDirtyFlag()
282
283 spec.lastFillTime = -1000
284 spec.lastEmptyTime = -1000
285
286 if not self.isServer then
287 SpecializationUtil.removeEventListener(self, "onUpdateTick", Pipe)
288 end
289end

onMovingToolChanged

Description
Definition
onMovingToolChanged()
Code
1298function Pipe:onMovingToolChanged(tool, transSpeed, dt)
1299 local spec = self.spec_pipe
1300 for _, pipeNode in ipairs(spec.nodes) do
1301 if pipeNode.node == tool.node then
1302 pipeNode.curTranslation = {tool.curTrans[1], tool.curTrans[2], tool.curTrans[3]}
1303 pipeNode.curRotation = {tool.curRot[1], tool.curRot[2], tool.curRot[3]}
1304 end
1305 end
1306end

onPostLoad

Description
Definition
onPostLoad()
Code
293function Pipe:onPostLoad(savegame)
294 local spec = self.spec_pipe
295
296 if savegame ~= nil and not savegame.resetVehicles then
297 local pipeState = savegame.xmlFile:getValue(savegame.key..".pipe#state", spec.currentState)
298 self:setPipeState(pipeState, true)
299 self:updatePipeNodes(999999, nil)
300
301 if spec.animation.name ~= nil then
302 local targetTime = 0
303 if pipeState ~= 1 then
304 targetTime = 1
305 end
306
307 self:setAnimationTime(spec.animation.name, targetTime, true)
308 end
309 end
310end

onReadStream

Description
Definition
onReadStream()
Code
335function Pipe:onReadStream(streamId, connection)
336 local spec = self.spec_pipe
337
338 local pipeState = streamReadUIntN(streamId, 2)
339 self:setPipeState(pipeState, true)
340
341 if streamReadBool(streamId) then
342 spec.nearestObjectInTriggers.objectId = NetworkUtil.readNodeObjectId(streamId)
343 spec.nearestObjectInTriggers.fillUnitIndex = streamReadUIntN(streamId, 4)
344 end
345end

onReadUpdateStream

Description
Definition
onReadUpdateStream()
Code
362function Pipe:onReadUpdateStream(streamId, timestamp, connection)
363 if connection:getIsServer() then
364 if streamReadBool(streamId) then
365 local spec = self.spec_pipe
366 if streamReadBool(streamId) then
367 spec.nearestObjectInTriggers.objectId = NetworkUtil.readNodeObjectId(streamId)
368 spec.nearestObjectInTriggers.fillUnitIndex = streamReadUIntN(streamId, 4)
369 else
370 spec.nearestObjectInTriggers.objectId = nil
371 spec.nearestObjectInTriggers.fillUnitIndex = 0
372 end
373 end
374 end
375end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
1310function Pipe:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
1311 if self.isClient then
1312 local spec = self.spec_pipe
1313 self:clearActionEventsTable(spec.actionEvents)
1314
1315 if isActiveForInputIgnoreSelection and spec.hasMovablePipe then
1316 local _, actionEventId = self:addPoweredActionEvent(spec.actionEvents, InputAction.TOGGLE_PIPE, self, Pipe.actionEventTogglePipe, false, true, false, true, nil)
1317 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_HIGH)
1318 self:updateActionEventText()
1319
1320 if spec.toggleableDischargeToGround then
1321 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_TIPSTATE_GROUND, self, Pipe.actionEventToggleDischargeToGround, false, true, false, true, nil)
1322 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
1323 g_inputBinding:setActionEventText(actionEventId, spec.dischargeToGroundState and spec.texts.stopTipToGround or spec.texts.startTipToGround)
1324 end
1325 end
1326 end
1327end

onUpdate

Description
Definition
onUpdate()
Code
393function Pipe:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
394 local spec = self.spec_pipe
395
396 self:updateActionEventText()
397
398 if spec.hasMovablePipe then
399 self:updatePipeNodes(dt, spec.nearestObjectInTriggers)
400 end
401end

onUpdateTick

Description
Definition
onUpdateTick()
Code
405function Pipe:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
406 if self.isServer then
407 self:updateNearestObjectInTriggers()
408
409 local spec = self.spec_pipe
410 local objectChanged = spec.nearestObjectInTriggers.objectId ~= spec.nearestObjectInTriggersSent.objectId
411 local fillUnitChanged = spec.nearestObjectInTriggers.fillUnitIndex ~= spec.nearestObjectInTriggersSent.fillUnitIndex
412 if objectChanged or fillUnitChanged then
413 spec.nearestObjectInTriggersSent.objectId = spec.nearestObjectInTriggers.objectId
414 spec.nearestObjectInTriggersSent.fillUnitIndex = spec.nearestObjectInTriggers.fillUnitIndex
415 self:raiseDirtyFlags(spec.dirtyFlag)
416 end
417
418 -- automatic unfold pipe if trailer is in trigger
419 if Platform.gameplay.automaticPipeUnfolding and not self:getIsAIActive() then
420 local unfoldPipe = spec.nearestObjectInTriggers.objectId ~= nil or spec.numUnloadTriggersInTriggers > 0
421
422 -- only unfold if the vehicle is filled
423 local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex())
424 if dischargeNode ~= nil then
425 local capacity = self:getFillUnitCapacity(dischargeNode.fillUnitIndex)
426 local fillLevel =self:getFillUnitFillLevel(dischargeNode.fillUnitIndex)
427 unfoldPipe = unfoldPipe and ((capacity == math.huge and (self.getIsTurnedOn == nil or self:getIsTurnedOn())) or fillLevel > 0)
428 end
429
430 if unfoldPipe then
431 if spec.targetState == 1 then
432 self:setPipeState(next(spec.unloadingStates))
433 end
434 else
435 if spec.targetState > 1 then
436 self:setPipeState(1)
437 end
438 end
439 end
440 end
441end

onWriteStream

Description
Definition
onWriteStream()
Code
349function Pipe:onWriteStream(streamId, connection)
350 local spec = self.spec_pipe
351
352 streamWriteUIntN(streamId, spec.targetState, 2)
353
354 if streamWriteBool(streamId, spec.nearestObjectInTriggersSent.objectId ~= nil) then
355 NetworkUtil.writeNodeObjectId(streamId, spec.nearestObjectInTriggersSent.objectId)
356 streamWriteUIntN(streamId, spec.nearestObjectInTriggersSent.fillUnitIndex, 4)
357 end
358end

onWriteUpdateStream

Description
Definition
onWriteUpdateStream()
Code
379function Pipe:onWriteUpdateStream(streamId, connection, dirtyMask)
380 if not connection:getIsServer() then
381 local spec = self.spec_pipe
382 if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then
383 if streamWriteBool(streamId, spec.nearestObjectInTriggersSent.objectId ~= nil) then
384 NetworkUtil.writeNodeObjectId(streamId, spec.nearestObjectInTriggersSent.objectId)
385 streamWriteUIntN(streamId, spec.nearestObjectInTriggersSent.fillUnitIndex, 4)
386 end
387 end
388 end
389end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
18function Pipe.prerequisitesPresent(specializations)
19 return SpecializationUtil.hasSpecialization(FillUnit, specializations) and SpecializationUtil.hasSpecialization(Dischargeable, specializations)
20end

registerEventListeners

Description
Definition
registerEventListeners()
Code
140function Pipe.registerEventListeners(vehicleType)
141 SpecializationUtil.registerEventListener(vehicleType, "onLoad", Pipe)
142 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Pipe)
143 SpecializationUtil.registerEventListener(vehicleType, "onDelete", Pipe)
144 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Pipe)
145 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Pipe)
146 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Pipe)
147 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Pipe)
148 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Pipe)
149 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Pipe)
150 SpecializationUtil.registerEventListener(vehicleType, "onMovingToolChanged", Pipe)
151 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Pipe)
152 SpecializationUtil.registerEventListener(vehicleType, "onDischargeStateChanged", Pipe)
153 SpecializationUtil.registerEventListener(vehicleType, "onAIImplementPrepare", Pipe)
154end

registerFunctions

Description
Definition
registerFunctions()
Code
102function Pipe.registerFunctions(vehicleType)
103 SpecializationUtil.registerFunction(vehicleType, "loadUnloadingTriggers", Pipe.loadUnloadingTriggers)
104 SpecializationUtil.registerFunction(vehicleType, "loadPipeNodes", Pipe.loadPipeNodes)
105 SpecializationUtil.registerFunction(vehicleType, "getIsPipeStateChangeAllowed", Pipe.getIsPipeStateChangeAllowed)
106 SpecializationUtil.registerFunction(vehicleType, "setPipeState", Pipe.setPipeState)
107 SpecializationUtil.registerFunction(vehicleType, "updatePipeNodes", Pipe.updatePipeNodes)
108 SpecializationUtil.registerFunction(vehicleType, "updateBendingRegulationNodes", Pipe.updateBendingRegulationNodes)
109 SpecializationUtil.registerFunction(vehicleType, "unloadingTriggerCallback", Pipe.unloadingTriggerCallback)
110 SpecializationUtil.registerFunction(vehicleType, "updateNearestObjectInTriggers", Pipe.updateNearestObjectInTriggers)
111 SpecializationUtil.registerFunction(vehicleType, "updateActionEventText", Pipe.updateActionEventText)
112 SpecializationUtil.registerFunction(vehicleType, "onDeletePipeObject", Pipe.onDeletePipeObject)
113 SpecializationUtil.registerFunction(vehicleType, "getPipeDischargeNodeIndex", Pipe.getPipeDischargeNodeIndex)
114 SpecializationUtil.registerFunction(vehicleType, "setPipeDischargeToGround", Pipe.setPipeDischargeToGround)
115end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
119function Pipe.registerOverwrittenFunctions(vehicleType)
120 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsDischargeNodeActive", Pipe.getIsDischargeNodeActive)
121 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn", Pipe.getCanBeTurnedOn)
122 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getTurnedOnNotAllowedWarning", Pipe.getTurnedOnNotAllowedWarning)
123 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsFoldAllowed", Pipe.getIsFoldAllowed)
124 SpecializationUtil.registerOverwrittenFunction(vehicleType, "handleDischarge", Pipe.handleDischarge)
125 SpecializationUtil.registerOverwrittenFunction(vehicleType, "handleDischargeRaycast", Pipe.handleDischargeRaycast)
126 SpecializationUtil.registerOverwrittenFunction(vehicleType, "dischargeToGround", Pipe.dischargeToGround)
127 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleDischargeToObject", Pipe.getCanToggleDischargeToObject)
128 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanToggleDischargeToGround", Pipe.getCanToggleDischargeToGround)
129 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadMovingToolFromXML", Pipe.loadMovingToolFromXML)
130 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsMovingToolActive", Pipe.getIsMovingToolActive)
131 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadCoverFromXML", Pipe.loadCoverFromXML)
132 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsNextCoverStateAllowed", Pipe.getIsNextCoverStateAllowed)
133 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", Pipe.getCanBeSelected)
134 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAIReadyToDrive", Pipe.getIsAIReadyToDrive)
135 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsAIPreparingToDrive", Pipe.getIsAIPreparingToDrive)
136end

registers

Description
Called on specialization initializing
Definition
registers()
Code
49function Pipe.registers(schema, basePath)
50 schema:register(XMLValueType.L10N_STRING, basePath .. "#turnOnStateWarning", "Turn on warning", "warning_firstSetPipeState")
51 schema:register(XMLValueType.INT, basePath .. "#dischargeNodeIndex", "Discharge node index", 1)
52 schema:register(XMLValueType.BOOL, basePath .. "#forceDischargeNodeIndex", "Force discharge node selection while changing pipe state. Can be deactivated e.g. if the selection is done by trailer spec etc.", true)
53 schema:register(XMLValueType.BOOL, basePath .. "#automaticDischarge", "Pipe is automatically starting to discharge as soon as it hits the trailer", true)
54 schema:register(XMLValueType.BOOL, basePath .. "#toggleableDischargeToGround", "Defines if the discharge to ground can be enabled separatly", false)
55 schema:register(XMLValueType.NODE_INDEX, basePath .. ".unloadingTriggers.unloadingTrigger(?)#node", "Unload trigger node")
56
57 schema:register(XMLValueType.STRING, basePath .. ".animation#name", "Pipe animation name")
58 schema:register(XMLValueType.FLOAT, basePath .. ".animation#speedScale", "Pipe animation speed scale", 1)
59 schema:register(XMLValueType.INT, basePath .. ".states#num", "Number of pipe states", 0)
60
61 schema:register(XMLValueType.NODE_INDEX, basePath .. ".pipeNodes.pipeNode(?)#node", "Pipe node")
62 schema:register(XMLValueType.NODE_INDEX, basePath .. ".pipeNodes.pipeNode(?)#subPipeNode", "Sub pipe node (Target rotation is devided between these two nodes depending on the X rotation ratio between #node and #node parent and #subPipeNode and #node parent)")
63 schema:register(XMLValueType.FLOAT, basePath .. ".pipeNodes.pipeNode(?)#subPipeNodeRatio", "Ratio between usage of this pipe node and sub node [0-1]", "Calculated based on rotation in i3d file")
64 schema:register(XMLValueType.BOOL, basePath .. ".pipeNodes.pipeNode(?)#autoAimXRotation", "Auto aim X rotation", false)
65 schema:register(XMLValueType.BOOL, basePath .. ".pipeNodes.pipeNode(?)#autoAimYRotation", "Auto aim Y rotation", false)
66 schema:register(XMLValueType.BOOL, basePath .. ".pipeNodes.pipeNode(?)#autoAimInvertZ", "Auto aim invert Z axis", false)
67
68 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".pipeNodes.pipeNode(?).state(?)#translation", "State translation")
69 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".pipeNodes.pipeNode(?).state(?)#rotation", "State translation")
70
71 schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".pipeNodes.pipeNode(?)#translationSpeeds", "Translation speeds")
72 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".pipeNodes.pipeNode(?)#rotationSpeeds", "Rotation speeds")
73
74 schema:register(XMLValueType.STRING, basePath .. ".pipeNodes.pipeNode(?)#minRotationLimits", "Min. rotation limit")
75 schema:register(XMLValueType.STRING, basePath .. ".pipeNodes.pipeNode(?)#maxRotationLimits", "Max. rotation limit")
76
77 schema:register(XMLValueType.INT, basePath .. ".pipeNodes.pipeNode(?)#foldPriority", "Fold priority", 0)
78 schema:register(XMLValueType.FLOAT, basePath .. ".pipeNodes.pipeNode(?)#bendingRegulation", "Bending angle regulation", 0)
79
80 schema:register(XMLValueType.NODE_INDEX, basePath .. ".pipeNodes.pipeNode(?).bendingRegulationNode(?)#node", "Bending regulation node", 0)
81 schema:register(XMLValueType.INT, basePath .. ".pipeNodes.pipeNode(?).bendingRegulationNode(?)#axis", "Bending regulation axis", 0)
82 schema:register(XMLValueType.INT, basePath .. ".pipeNodes.pipeNode(?).bendingRegulationNode(?)#direction", "Bending regulation direction", 0)
83
84 schema:register(XMLValueType.VECTOR_N, basePath .. ".states#unloading", "Unloading states")
85 schema:register(XMLValueType.VECTOR_N, basePath .. ".states#autoAiming", "Auto aim states")
86 schema:register(XMLValueType.VECTOR_N, basePath .. ".states#turnOnAllowed", "Turn on allowed states")
87
88 schema:register(XMLValueType.INT, basePath .. ".states.state(?)#stateIndex", "State index")
89 schema:register(XMLValueType.INT, basePath .. ".states.state(?)#dischargeNodeIndex", "Discharge node index")
90
91 schema:register(XMLValueType.FLOAT, basePath .. "#foldMinLimit", "Fold min. limit", 0)
92 schema:register(XMLValueType.FLOAT, basePath .. "#foldMaxLimit", "Fold max. limit", 1)
93
94 schema:register(XMLValueType.INT, basePath .. "#foldMinState", "Fold min. state", 1)
95 schema:register(XMLValueType.INT, basePath .. "#foldMaxState", "Fold max. state", "Num. of states")
96
97 schema:register(XMLValueType.BOOL, basePath .. "#aiFoldedPipeUsesTrailerSpace", "Defines if the folded pipe uses the space of the trailer to discharge", false)
98end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
328function Pipe:saveToXMLFile(xmlFile, key, usedModNames)
329 local spec = self.spec_pipe
330 xmlFile:setValue(key.."#state", MathUtil.clamp(spec.currentState, 1, spec.numStates))
331end

setPipeDischargeToGround

Description
Definition
setPipeDischargeToGround()
Code
1246function Pipe:setPipeDischargeToGround(state, noEventSend)
1247 local spec = self.spec_pipe
1248 if state == nil then
1249 state = not spec.dischargeToGroundState
1250 end
1251
1252 if state ~= spec.dischargeToGroundState then
1253 spec.dischargeToGroundState = state
1254
1255 local actionEvent = spec.actionEvents[InputAction.TOGGLE_TIPSTATE_GROUND]
1256 if actionEvent ~= nil then
1257 g_inputBinding:setActionEventText(actionEvent.actionEventId, state and spec.texts.stopTipToGround or spec.texts.startTipToGround)
1258 end
1259
1260 SetPipeDischargeToGroundEvent.sendEvent(self, state, noEventSend)
1261 end
1262end

setPipeState

Description
Definition
setPipeState()
Code
613function Pipe:setPipeState(pipeState, noEventSend)
614 local spec = self.spec_pipe
615
616 pipeState = math.min(pipeState, spec.numStates)
617 if spec.targetState ~= pipeState then
618 if noEventSend == nil or noEventSend == false then
619 if g_server ~= nil then
620 g_server:broadcastEvent(SetPipeStateEvent.new(self, pipeState))
621 else
622 g_client:getServerConnection():sendEvent(SetPipeStateEvent.new(self, pipeState), nil, nil, self)
623 end
624 end
625 spec.targetState = pipeState
626 spec.currentState = 0
627
628 if spec.animation ~= nil then
629 if pipeState == 1 then
630 self:playAnimation(spec.animation.name, -spec.animation.speedScale, self:getAnimationTime(spec.animation.name), true)
631 else
632 self:playAnimation(spec.animation.name, spec.animation.speedScale, self:getAnimationTime(spec.animation.name), true)
633 end
634 end
635
636 if spec.forceDischargeNodeIndex then
637 self:setCurrentDischargeNodeIndex(self:getPipeDischargeNodeIndex(pipeState))
638 end
639 end
640end

unloadingTriggerCallback

Description
Definition
unloadingTriggerCallback()
Code
847function Pipe:unloadingTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
848 if onEnter or onLeave then
849 local object = g_currentMission:getNodeObject(otherId)
850
851 if object ~= nil and object ~= self and object:isa(Vehicle) then
852 if object.getFillUnitIndexFromNode ~= nil then
853 local fillUnitIndex = object:getFillUnitIndexFromNode(otherId)
854 if fillUnitIndex ~= nil then
855 local spec = self.spec_pipe
856
857 local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex())
858 if dischargeNode ~= nil then
859 local fillTypes = self:getFillUnitSupportedFillTypes(dischargeNode.fillUnitIndex)
860
861 -- objects is only valid if it supports at least one of the harvesters fill types
862 local objectSupportsFillType = false
863 for fillType, _ in pairs(fillTypes) do
864 if object:getFillUnitSupportsFillType(fillUnitIndex, fillType) then
865 objectSupportsFillType = true
866 break
867 end
868 end
869
870 if objectSupportsFillType then
871 if onEnter then
872 if spec.objectsInTriggers[object] == nil then
873 spec.objectsInTriggers[object] = 0
874 spec.numObjectsInTriggers = spec.numObjectsInTriggers + 1
875 if object.addDeleteListener ~= nil then
876 object:addDeleteListener(self, "onDeletePipeObject")
877 end
878 end
879
880 spec.objectsInTriggers[object] = spec.objectsInTriggers[object] + 1
881 else
882 spec.objectsInTriggers[object] = spec.objectsInTriggers[object] - 1
883 if spec.objectsInTriggers[object] == 0 then
884 spec.objectsInTriggers[object] = nil
885 spec.numObjectsInTriggers = spec.numObjectsInTriggers - 1
886 if object.removeDeleteListener ~= nil then
887 object:removeDeleteListener(self)
888 end
889 end
890 end
891 end
892 end
893 end
894 end
895 elseif object ~= nil and object ~= self and object:isa(UnloadTrigger) then
896 local spec = self.spec_pipe
897 if onEnter then
898 if spec.unloadTriggersInTriggers[object] == nil then
899 spec.unloadTriggersInTriggers[object] = 0
900 spec.numUnloadTriggersInTriggers = spec.numUnloadTriggersInTriggers + 1
901 if object.addDeleteListener ~= nil then
902 object:addDeleteListener(self, "onDeletePipeObject")
903 end
904 end
905
906 spec.unloadTriggersInTriggers[object] = spec.unloadTriggersInTriggers[object] + 1
907 else
908 spec.unloadTriggersInTriggers[object] = spec.unloadTriggersInTriggers[object] - 1
909 if spec.unloadTriggersInTriggers[object] == 0 then
910 spec.unloadTriggersInTriggers[object] = nil
911 spec.numUnloadTriggersInTriggers = spec.numUnloadTriggersInTriggers - 1
912 if object.removeDeleteListener ~= nil then
913 object:removeDeleteListener(self)
914 end
915 end
916 end
917 end
918 end
919end

updateActionEventText

Description
Definition
updateActionEventText()
Code
969function Pipe:updateActionEventText()
970 local spec = self.spec_pipe
971
972 -- check if action event already exists. Nil on loading
973 local actionEvent = spec.actionEvents[InputAction.TOGGLE_PIPE]
974 if actionEvent ~= nil then
975 local showAction = false
976 if spec.targetState == spec.numStates then
977 if self:getIsPipeStateChangeAllowed(1) then
978 g_inputBinding:setActionEventText(actionEvent.actionEventId, spec.texts.pipeIn)
979 showAction = true
980 end
981 else
982 local nextState = spec.targetState + 1
983 if self:getIsPipeStateChangeAllowed(nextState) then
984 local pipeStateName = ""
985 if spec.numUnloadingStates > 1 and spec.numUnloadingStates ~= spec.numStates then
986 pipeStateName = string.format(" [%d]", nextState - 1)
987 local dischargeNodeIndex = self:getPipeDischargeNodeIndex(nextState)
988 local dischargeNode = self:getDischargeNodeByIndex(dischargeNodeIndex)
989 local fillTypeIndex = self:getFillUnitFillType(dischargeNode.fillUnitIndex)
990 if fillTypeIndex ~= FillType.UNKNOWN then
991 local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex)
992 if fillType ~= nil then
993 pipeStateName = string.format(" [%d, %s]", nextState - 1, fillType.title)
994 end
995 end
996 end
997
998 g_inputBinding:setActionEventText(actionEvent.actionEventId, string.format(spec.texts.pipeOut, pipeStateName))
999 showAction = true
1000 end
1001 end
1002
1003 g_inputBinding:setActionEventActive(actionEvent.actionEventId, showAction)
1004 end
1005end

updateBendingRegulationNodes

Description
Definition
updateBendingRegulationNodes()
Code
824function Pipe:updateBendingRegulationNodes(pipeNode, distance)
825 local _, dirY, _ = localDirectionToWorld(pipeNode.node, 0, 1, 0)
826
827 for _, regulationNode in ipairs(pipeNode.regulationNodes) do
828 local regulationAngle = dirY*pipeNode.bendingRegulation
829 local weights = regulationNode.weights
830 local startRotation = regulationNode.startRotation
831 setRotation(regulationNode.node, startRotation[1]+weights[1]*regulationAngle,
832 startRotation[2]+weights[2]*regulationAngle,
833 startRotation[3]+weights[3]*regulationAngle)
834
835 if VehicleDebug.state == VehicleDebug.DEBUG then
836 local x1, y1, z1 = getWorldTranslation(regulationNode.node)
837 local x2, y2, z2 = localToWorld(regulationNode.node, 0, -10, 0)
838 drawDebugLine(x1, y1, z1, 0, 0, 1, x2, y2, z2, 0, 0, 1)
839 end
840 end
841
842 return math.sin(dirY*pipeNode.bendingRegulation) * distance
843end

updateNearestObjectInTriggers

Description
Definition
updateNearestObjectInTriggers()
Code
923function Pipe:updateNearestObjectInTriggers()
924 local spec = self.spec_pipe
925
926 spec.nearestObjectInTriggers.objectId = nil
927 spec.nearestObjectInTriggers.fillUnitIndex = 0
928
929 local minDistance = math.huge
930 local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex())
931 if dischargeNode ~= nil then
932 local checkNode = Utils.getNoNil(dischargeNode.node, self.components[1].node)
933
934 for object, _ in pairs(spec.objectsInTriggers) do
935 local outputFillType = self:getFillUnitLastValidFillType(dischargeNode.fillUnitIndex)
936
937 for fillUnitIndex, _ in ipairs(object.spec_fillUnit.fillUnits) do
938 local allowedToFillByPipe = object:getFillUnitSupportsToolType(fillUnitIndex, ToolType.DISCHARGEABLE)
939 local supportsFillType = object:getFillUnitSupportsFillType(fillUnitIndex, outputFillType) or outputFillType == FillType.UNKNOWN
940 local fillLevel = object:getFillUnitFreeCapacity(fillUnitIndex, outputFillType, self:getOwnerFarmId())
941
942 if allowedToFillByPipe and supportsFillType and fillLevel > 0 then
943 local targetPoint = object:getFillUnitAutoAimTargetNode(fillUnitIndex)
944 local exactFillRootNode = object:getFillUnitExactFillRootNode(fillUnitIndex)
945
946 if targetPoint == nil then
947 targetPoint = exactFillRootNode
948 end
949
950 if targetPoint ~= nil then
951 local distance = calcDistanceFrom(checkNode, targetPoint)
952 if distance < minDistance then
953 minDistance = distance
954 spec.nearestObjectInTriggers.objectId = NetworkUtil.getObjectId(object)
955 spec.nearestObjectInTriggers.fillUnitIndex = fillUnitIndex
956 break
957 end
958 end
959 end
960 end
961 end
962 else
963 Logging.xmlWarning(self.xmlFile, "Unable to find discharge node index '%d' for pipe", self:getPipeDischargeNodeIndex())
964 end
965end

updatePipeNodes

Description
Definition
updatePipeNodes()
Code
644function Pipe:updatePipeNodes(dt, nearestObjectInTrigger)
645 local spec = self.spec_pipe
646 local object = nil
647 if nearestObjectInTrigger ~= nil then
648 object = NetworkUtil.getObject(nearestObjectInTrigger.objectId)
649 end
650
651 local doAutoAiming = object ~= nil and entityExists(object.components[1].node) and spec.autoAimingStates[spec.currentState]
652
653 if spec.currentState ~= spec.targetState or doAutoAiming then
654 local priority = spec.targetState ~= spec.numStates and "foldPriority" or "inverseFoldPriority"
655
656 local fillAutoAimTargetNode
657 local autoAimX, autoAimY, autoAimZ
658 if doAutoAiming then
659 fillAutoAimTargetNode = object:getFillUnitAutoAimTargetNode(nearestObjectInTrigger.fillUnitIndex)
660 if fillAutoAimTargetNode == nil then
661 fillAutoAimTargetNode = object:getFillUnitExactFillRootNode(nearestObjectInTrigger.fillUnitIndex)
662 end
663
664 autoAimX, autoAimY, autoAimZ = getWorldTranslation(fillAutoAimTargetNode)
665
666 if VehicleDebug.state == VehicleDebug.DEBUG then
667 DebugUtil.drawDebugGizmoAtWorldPos(autoAimX, autoAimY, autoAimZ, 0, 0, 1, 0, 1, 0, getName(fillAutoAimTargetNode), false)
668 end
669 end
670
671 local moved = false
672 for i=1, #spec.nodes do
673 local nodeMoved = false
674 local pipeNode = spec.nodes[i]
675
676 local nodeAutoAimY = autoAimY
677 if pipeNode.bendingRegulation > 0 then
678 if fillAutoAimTargetNode ~= nil then
679 local distance = calcDistanceFrom(pipeNode.node, fillAutoAimTargetNode)
680 local regulation = self:updateBendingRegulationNodes(pipeNode, distance)
681 nodeAutoAimY = autoAimY - regulation
682 end
683 end
684
685 local state = pipeNode.states[spec.targetState]
686 if pipeNode.translationSpeeds ~= nil then
687 for axis=1, 3 do
688 if math.abs(pipeNode.curTranslation[axis] - state.translation[axis]) > 0.000001 then
689 nodeMoved = true
690 if pipeNode.curTranslation[axis] < state.translation[axis] then
691 pipeNode.curTranslation[axis] = math.min(pipeNode.curTranslation[axis] + dt*pipeNode.translationSpeeds[axis], state.translation[axis])
692 else
693 pipeNode.curTranslation[axis] = math.max(pipeNode.curTranslation[axis] - dt*pipeNode.translationSpeeds[axis], state.translation[axis])
694 end
695 end
696 end
697 setTranslation(pipeNode.node, pipeNode.curTranslation[1],pipeNode.curTranslation[2],pipeNode.curTranslation[3])
698 end
699 if pipeNode.rotationSpeeds ~= nil then
700 local changed = false
701 for axis=1, 3 do
702 local targetRotation = state.rotation[axis]
703 if doAutoAiming then
704 if pipeNode.autoAimXRotation and axis == 1 then
705 local x, y, z = getWorldTranslation(pipeNode.node)
706
707 if VehicleDebug.state == VehicleDebug.DEBUG then
708 if pipeNode.subPipeNode == nil then
709 drawDebugLine(x, y, z, 1, 0, 0, autoAimX, nodeAutoAimY, autoAimZ, 1, 0, 0)
710 else
711 local x1, y1, z1 = getWorldTranslation(pipeNode.node)
712 local x2, y2, z2 = localToWorld(pipeNode.node, 0, 0, 3)
713 drawDebugLine(x1, y1, z1, 1, 1, 0, x2, y2, z2, 1, 1, 0)
714
715 DebugUtil.drawDebugGizmoAtWorldPos(x2, y2, z2, 0, 0, 1, 0, 1, 0, string.format("ratio: %.2f", pipeNode.subPipeNodeRatio), false)
716 end
717 end
718
719 local _, lDirY, lDirZ = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, nodeAutoAimY-y, autoAimZ-z)
720 targetRotation = -math.atan2(lDirY, lDirZ)
721
722 if pipeNode.subPipeNode ~= nil then
723 targetRotation = targetRotation * pipeNode.subPipeNodeRatio
724 end
725
726 if pipeNode.autoAimInvertZ then
727 targetRotation = targetRotation+math.pi
728 end
729 targetRotation = MathUtil.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[axis])
730 elseif pipeNode.autoAimYRotation and axis == 2 then
731 local x, y, z = getWorldTranslation(pipeNode.node)
732 local lDirX, _, lDirZ = worldDirectionToLocal(getParent(pipeNode.node), autoAimX-x, nodeAutoAimY-y, autoAimZ-z)
733 targetRotation = math.atan2(lDirX, lDirZ)
734 if pipeNode.autoAimInvertZ then
735 targetRotation = targetRotation+math.pi
736 end
737 targetRotation = MathUtil.normalizeRotationForShortestPath(targetRotation, pipeNode.curRotation[axis])
738 end
739 end
740 if pipeNode.minRotationLimits ~= nil and pipeNode.maxRotationLimits ~= nil then
741 if math.abs(targetRotation) > (2 * math.pi) then
742 targetRotation = targetRotation % (2 * math.pi)
743 end
744
745 if pipeNode.minRotationLimits[axis] ~= nil then
746 targetRotation = math.max(targetRotation, pipeNode.minRotationLimits[axis])
747 end
748 if pipeNode.maxRotationLimits[axis] ~= nil then
749 targetRotation = math.min(targetRotation, pipeNode.maxRotationLimits[axis])
750 end
751 end
752 if math.abs(pipeNode.curRotation[axis] - targetRotation) > 0.00001 then
753 changed = true
754 local rotationAllowed = true
755 -- priorities only while folding the pipe, not while auto aiming
756 if not doAutoAiming then
757 for j=1, #spec.nodes do
758 local pipeNodeToCheck = spec.nodes[j]
759 if pipeNodeToCheck[priority] > pipeNode[priority] then
760 for l=1, 3 do
761 if pipeNodeToCheck.curRotation[l] ~= pipeNodeToCheck.lastTargetRotation[l] then
762 rotationAllowed = false
763 break
764 end
765 end
766 end
767 end
768 end
769
770 if rotationAllowed then
771 nodeMoved = true
772 if pipeNode.curRotation[axis] < targetRotation then
773 pipeNode.curRotation[axis] = math.min(pipeNode.curRotation[axis] + dt*pipeNode.rotationSpeeds[axis], targetRotation)
774 else
775 pipeNode.curRotation[axis] = math.max(pipeNode.curRotation[axis] - dt*pipeNode.rotationSpeeds[axis], targetRotation)
776 end
777 if pipeNode.curRotation[axis] > 2*math.pi then
778 pipeNode.curRotation[axis] = pipeNode.curRotation[axis] - 2*math.pi
779 elseif pipeNode.curRotation[axis] < -2*math.pi then
780 pipeNode.curRotation[axis] = pipeNode.curRotation[axis] + 2*math.pi
781 end
782
783 pipeNode.lastTargetRotation[axis] = targetRotation
784 end
785 end
786 end
787
788 if changed then
789 setRotation(pipeNode.node, pipeNode.curRotation[1], pipeNode.curRotation[2], pipeNode.curRotation[3])
790 end
791 end
792 moved = moved or nodeMoved
793
794 if nodeMoved and self.setMovingToolDirty ~= nil then
795 self:setMovingToolDirty(pipeNode.node)
796 end
797 end
798
799 if #spec.nodes == 0 and spec.animation.name ~= nil then
800 if self:getIsAnimationPlaying(spec.animation.name) then
801 moved = true
802 end
803 end
804
805 if not moved then
806 spec.currentState = spec.targetState
807 end
808 else
809 if self:getDischargeState() == Dischargeable.DISCHARGE_STATE_GROUND then
810 local dischargeNode = self:getDischargeNodeByIndex(self:getPipeDischargeNodeIndex())
811 if dischargeNode ~= nil then
812 for _,pipeNode in ipairs(spec.nodes) do
813 if pipeNode.bendingRegulation > 0 then
814 self:updateBendingRegulationNodes(pipeNode, dischargeNode.dischargeDistance)
815 end
816 end
817 end
818 end
819 end
820end