LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

FillUnit

Description
Specialization for vehicles with any sort of capacity or tank. Manages filltypes, capacities, fillLevel changes
Functions

actionEventConsoleFillUnitDec

Description
Definition
actionEventConsoleFillUnitDec()
Code
2879function FillUnit.actionEventConsoleFillUnitDec(self, actionName, inputValue, callbackState, isAnalog)
2880 if self:getIsSelected() then
2881 local fillType = self:getFillUnitFillType(1)
2882 self:addFillUnitFillLevel(self:getOwnerFarmId(), 1, -1000, fillType, ToolType.UNDEFINED, nil)
2883 end
2884end

actionEventConsoleFillUnitInc

Description
Definition
actionEventConsoleFillUnitInc()
Code
2866function FillUnit.actionEventConsoleFillUnitInc(self, actionName, inputValue, callbackState, isAnalog)
2867 if self:getIsSelected() then
2868 local fillType = self:getFillUnitFillType(1)
2869 if fillType == FillType.UNKNOWN then
2870 local fillUnit = self:getFillUnitByIndex(1)
2871 fillType = next(fillUnit.supportedFillTypes)
2872 end
2873 self:addFillUnitFillLevel(self:getOwnerFarmId(), 1, 1000, fillType, ToolType.UNDEFINED, nil)
2874 end
2875end

actionEventConsoleFillUnitNext

Description
Definition
actionEventConsoleFillUnitNext()
Code
2838function FillUnit.actionEventConsoleFillUnitNext(self, actionName, inputValue, callbackState, isAnalog)
2839 if self:getIsSelected() then
2840 local fillType = self:getFillUnitFillType(1)
2841 local fillUnit = self:getFillUnitByIndex(1)
2842 local found = false
2843 local nextFillType = nil
2844 for supportedFillType,_ in pairs(fillUnit.supportedFillTypes) do
2845 if not found then
2846 if supportedFillType == fillType then
2847 found = true
2848 end
2849 else
2850 nextFillType = supportedFillType
2851 break
2852 end
2853 end
2854
2855 if nextFillType == nil then
2856 nextFillType = next(fillUnit.supportedFillTypes)
2857 end
2858
2859 self:addFillUnitFillLevel(self:getOwnerFarmId(), 1, -math.huge, fillType, ToolType.UNDEFINED, nil)
2860 self:addFillUnitFillLevel(self:getOwnerFarmId(), 1, 100, nextFillType, ToolType.UNDEFINED, nil)
2861 end
2862end

actionEventUnload

Description
Definition
actionEventUnload()
Code
2888function FillUnit.actionEventUnload(self, actionName, inputValue, callbackState, isAnalog)
2889 self:unloadFillUnits()
2890end

addFillTypeSources

Description
Definition
addFillTypeSources()
Code
2426function FillUnit.addFillTypeSources(sources, currentVehicle, excludeVehicle, fillTypes)
2427 if currentVehicle ~= excludeVehicle then
2428 local curVehicle = currentVehicle.spec_fillUnit
2429 if curVehicle ~= nil then
2430 for fillUnitIndex2, fillUnit2 in pairs(curVehicle.fillUnits) do
2431 for _,fillType in pairs(fillTypes) do
2432 if fillUnit2.supportedFillTypes[fillType] then
2433 if sources[fillType] == nil then
2434 sources[fillType] = {}
2435 end
2436 table.insert(sources[fillType], {vehicle=currentVehicle, fillUnitIndex=fillUnitIndex2})
2437 end
2438 end
2439 end
2440 end
2441 end
2442
2443 if currentVehicle.getAttachedImplements ~= nil then
2444 local attachedImplements = currentVehicle:getAttachedImplements()
2445 for _,implement in pairs(attachedImplements) do
2446 if implement.object ~= nil then
2447 FillUnit.addFillTypeSources(sources, implement.object, excludeVehicle, fillTypes)
2448 end
2449 end
2450 end
2451end

addFillUnitFillLevel

Description
Definition
addFillUnitFillLevel()
Code
1282function FillUnit:addFillUnitFillLevel(farmId, fillUnitIndex, fillLevelDelta, fillTypeIndex, toolType, fillPositionData)
1283 local spec = self.spec_fillUnit
1284 spec.isInfoDirty = true
1285
1286 -- Check for permission. Do allow vehicles with farmId 0 (all-access vehicles).
1287 -- Only check for access if value is being removed
1288 if fillLevelDelta < 0 and not g_currentMission.accessHandler:canFarmAccess(farmId, self, true) then
1289 return 0
1290 end
1291
1292 -- If this fillunit belongs to a mounted object (pallet), check that the controller of the object
1293 -- is allowed to empty the fill unit.
1294 if self.getMountObject ~= nil then
1295 local mounter = self:getDynamicMountObject() or self:getMountObject()
1296 if mounter ~= nil then
1297 -- if the active farm of the mounter has NO access to farmId fill unit: disallow
1298 if not g_currentMission.accessHandler:canFarmAccess(mounter:getActiveFarm(), self, true) then
1299 return 0
1300 end
1301 end
1302 end
1303
1304 local fillUnit = spec.fillUnits[fillUnitIndex]
1305 if fillUnit ~= nil then
1306 if fillLevelDelta > 0 then
1307 if not fillUnit.ignoreFillLimit then
1308 if g_currentMission.missionInfo.trailerFillLimit and self:getMaxComponentMassReached() then
1309 return 0
1310 end
1311 end
1312 end
1313
1314 if not self:getFillUnitSupportsToolTypeAndFillType(fillUnitIndex, toolType, fillTypeIndex) then
1315 return 0
1316 end
1317
1318 -- apply limit only on server side, client will receive the correct data
1319 if self.isServer then
1320 if fillLevelDelta > 0 then
1321 if not fillUnit.ignoreFillLimit then
1322 if g_currentMission.missionInfo.trailerFillLimit then
1323 local maxMassToApply = self:getAvailableComponentMass()
1324 local fillTypeDesc = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex)
1325 if fillTypeDesc ~= nil then
1326 fillLevelDelta = math.min(fillLevelDelta, maxMassToApply / fillTypeDesc.massPerLiter)
1327 end
1328 end
1329 end
1330 end
1331 end
1332
1333 local oldFillLevel = fillUnit.fillLevel
1334 local capacity = fillUnit.capacity
1335 if capacity == 0 then
1336 capacity = math.huge
1337 end
1338
1339 local fillTypeChanged = false
1340 if fillUnit.fillType == fillTypeIndex then
1341 fillUnit.fillLevel = math.max(0, math.min(capacity, oldFillLevel + fillLevelDelta))
1342 else
1343 if fillLevelDelta > 0 then
1344 local allowFillType = self:getFillUnitAllowsFillType(fillUnitIndex, fillTypeIndex)
1345 if allowFillType then
1346 local oldFillTypeIndex = fillUnit.fillType
1347 if oldFillLevel > 0 then
1348 self:addFillUnitFillLevel(farmId, fillUnitIndex, -math.huge, fillUnit.fillType, toolType, fillPositionData)
1349 end
1350 oldFillLevel = 0
1351 fillUnit.fillLevel = math.max(0, math.min(capacity, fillLevelDelta))
1352 fillUnit.fillType = fillTypeIndex
1353
1354 fillTypeChanged = true
1355 self.rootVehicle:raiseStateChange(Vehicle.STATE_CHANGE_FILLTYPE_CHANGE)
1356 SpecializationUtil.raiseEvent(self, "onChangedFillType", fillUnitIndex, fillTypeIndex, oldFillTypeIndex)
1357 else
1358 return 0
1359 end
1360 end
1361 end
1362
1363 -- reset fill level if below threshold due to float 32 inaccuracy
1364 if fillUnit.fillLevel < 0.00001 then
1365 fillUnit.fillLevel = 0
1366 end
1367
1368 if fillUnit.fillLevel > 0 then
1369 fillUnit.lastValidFillType = fillUnit.fillType
1370 else
1371 SpecializationUtil.raiseEvent(self, "onChangedFillType", fillUnitIndex, FillType.UNKNOWN, fillUnit.fillType)
1372 fillUnit.fillType = FillType.UNKNOWN
1373
1374 if not fillUnit.fillTypeToDisplayIsPersistent then
1375 fillUnit.fillTypeToDisplay = FillType.UNKNOWN
1376 end
1377
1378 if not fillUnit.fillLevelToDisplayIsPersistent then
1379 fillUnit.fillLevelToDisplay = nil
1380 end
1381 end
1382
1383 local appliedDelta = fillUnit.fillLevel - oldFillLevel
1384
1385 if self.isServer then
1386 -- prepare for network
1387 if fillUnit.synchronizeFillLevel then
1388 local hasChanged = false
1389 if fillUnit.fillLevel ~= fillUnit.fillLevelSent then
1390 local maxValue = 2^fillUnit.synchronizationNumBits - 1
1391 local levelPerBit = fillUnit.capacity / maxValue
1392 local changedLevel = math.abs(fillUnit.fillLevel - fillUnit.fillLevelSent)
1393
1394 if changedLevel > levelPerBit then
1395 fillUnit.fillLevelSent = fillUnit.fillLevel
1396 hasChanged = true
1397 end
1398 end
1399 if fillUnit.fillType ~= fillUnit.fillTypeSent then
1400 fillUnit.fillTypeSent = fillUnit.fillType
1401 hasChanged = true
1402 end
1403 if fillUnit.lastValidFillType ~= fillUnit.lastValidFillTypeSent then
1404 fillUnit.lastValidFillTypeSent = fillUnit.lastValidFillType
1405 hasChanged = true
1406 end
1407 if hasChanged then
1408 self:raiseDirtyFlags(spec.dirtyFlag)
1409 end
1410 end
1411 end
1412
1413 if fillUnit.updateMass then
1414 self:setMassDirty()
1415 end
1416
1417 self:updateFillUnitAutoAimTarget(fillUnit)
1418
1419 if self.isClient then
1420 self:updateAlarmTriggers(fillUnit.alarmTriggers)
1421 self:updateFillUnitFillPlane(fillUnit)
1422 self:updateMeasurementNodes(fillUnit, 0, true)
1423
1424 if fillTypeChanged then
1425 self:updateFillTypeMaterials(fillUnit.fillTypeMaterials, fillUnit.fillType)
1426 end
1427 end
1428
1429 SpecializationUtil.raiseEvent(self, "onFillUnitFillLevelChanged", fillUnitIndex, fillLevelDelta, fillTypeIndex, toolType, fillPositionData, appliedDelta)
1430
1431 if self.isServer then
1432 if spec.removeVehicleIfEmpty and fillUnit.fillLevel <= 0.3 then
1433 if spec.removeVehicleDelay == 0 then
1434 g_currentMission:removeVehicle(self)
1435 else
1436 Timer.createOneshot(spec.removeVehicleDelay, function()
1437 g_currentMission:removeVehicle(self)
1438 end)
1439 end
1440 end
1441 end
1442
1443 if appliedDelta > 0 then
1444 -- display default effects
1445 if #spec.fillEffects > 0 then
1446 g_effectManager:setFillType(spec.fillEffects, fillUnit.fillType)
1447 g_effectManager:startEffects(spec.fillEffects)
1448
1449 spec.activeFillEffects[spec.fillEffects] = 500
1450 end
1451
1452 -- display fill unit effects
1453 if #fillUnit.fillEffects > 0 then
1454 g_effectManager:setFillType(fillUnit.fillEffects, fillUnit.fillType)
1455 g_effectManager:startEffects(fillUnit.fillEffects)
1456
1457 spec.activeFillEffects[fillUnit.fillEffects] = 500
1458 end
1459
1460
1461 -- start default animation nodes
1462 if #spec.animationNodes > 0 then
1463 g_animationManager:startAnimations(spec.animationNodes)
1464 spec.activeFillAnimations[spec.animationNodes] = 500
1465 end
1466
1467 -- start fill unit animation nodes
1468 if #fillUnit.animationNodes > 0 then
1469 g_animationManager:startAnimations(fillUnit.animationNodes)
1470 spec.activeFillAnimations[fillUnit.animationNodes] = 500
1471 end
1472
1473 if fillUnit.fillAnimation ~= nil then
1474 if fillUnit.fillAnimationLoadTime ~= nil then
1475 local animTime = self:getAnimationTime(fillUnit.fillAnimation)
1476 local direction = MathUtil.sign(fillUnit.fillAnimationLoadTime-animTime)
1477 if direction ~= 0 then
1478 self:playAnimation(fillUnit.fillAnimation, direction, animTime)
1479 self:setAnimationStopTime(fillUnit.fillAnimation, fillUnit.fillAnimationLoadTime)
1480 end
1481 end
1482 end
1483 end
1484
1485 if appliedDelta ~= 0 then
1486 if fillUnit.fillLevelAnimationName ~= nil then
1487 if fillUnit.fillLevel > 0 or fillUnit.fillLevelAnimationResetOnEmpty then
1488 local targetTime = fillUnit.fillLevel / fillUnit.capacity
1489 local direction = 1
1490 if targetTime < self:getAnimationTime(fillUnit.fillLevelAnimationName) then
1491 direction = -1
1492 end
1493 self:playAnimation(fillUnit.fillLevelAnimationName, direction, self:getAnimationTime(fillUnit.fillLevelAnimationName), true)
1494 self:setAnimationStopTime(fillUnit.fillLevelAnimationName, targetTime)
1495 end
1496 end
1497 end
1498
1499 if fillUnit.fillLevel < 0.0001 then
1500 if fillUnit.fillAnimation ~= nil then
1501 if fillUnit.fillAnimationEmptyTime ~= nil then
1502 local animTime = self:getAnimationTime(fillUnit.fillAnimation)
1503 local direction = MathUtil.sign(fillUnit.fillAnimationEmptyTime-animTime)
1504 self:playAnimation(fillUnit.fillAnimation, direction, animTime)
1505 self:setAnimationStopTime(fillUnit.fillAnimation, fillUnit.fillAnimationEmptyTime)
1506 end
1507 end
1508 end
1509
1510 if self.setDashboardsDirty ~= nil then
1511 self:setDashboardsDirty()
1512 end
1513
1514 FillUnit.updateUnloadActionDisplay(self)
1515
1516 return appliedDelta
1517 end
1518
1519 return 0
1520end

addFillUnitTrigger

Description
Adds fill trigger
Definition
addFillUnitTrigger(table trigger, integer fillTypeIndex)
Arguments
tabletriggertrigger
integerfillTypeIndexfillTypeIndex
Code
2023function FillUnit:addFillUnitTrigger(trigger, fillTypeIndex, fillUnitIndex)
2024 local spec = self.spec_fillUnit
2025 if #spec.fillTrigger.triggers == 0 then
2026 g_currentMission.activatableObjectsSystem:addActivatable(spec.fillTrigger.activatable)
2027 spec.fillTrigger.activatable:setFillType(fillTypeIndex)
2028
2029 -- automatic filling for mobile version
2030 if self.isServer and Platform.gameplay.automaticFilling then
2031 self:setFillUnitIsFilling(true)
2032 end
2033 end
2034 table.addElement(spec.fillTrigger.triggers, trigger)
2035 SpecializationUtil.raiseEvent(self, "onAddedFillUnitTrigger", fillTypeIndex, fillUnitIndex, #spec.fillTrigger.triggers)
2036
2037 self:updateFillUnitTriggers()
2038end

addNodeObjectMapping

Description
Definition
addNodeObjectMapping()
Code
2182function FillUnit:addNodeObjectMapping(superFunc, list)
2183 superFunc(self, list)
2184
2185 local spec = self.spec_fillUnit
2186
2187 for _,fillUnit in pairs(spec.fillUnits) do
2188 if fillUnit.fillRootNode ~= nil then
2189 list[fillUnit.fillRootNode] = self
2190 end
2191 if fillUnit.exactFillRootNode ~= nil then
2192 list[fillUnit.exactFillRootNode] = self
2193 end
2194 end
2195end

debugGetSupportedFillTypesPerFillUnit

Description
Returns table with key=fillUnitIndex and value=array of fillTypeIds
Definition
debugGetSupportedFillTypesPerFillUnit()
Code
2416function FillUnit:debugGetSupportedFillTypesPerFillUnit()
2417 local fillUnitToFillTypes = {}
2418 for _, fillUnit in ipairs(self:getFillUnits()) do
2419 fillUnitToFillTypes[fillUnit.fillUnitIndex] = fillUnit.supportedFillTypes
2420 end
2421 return fillUnitToFillTypes
2422end

emptyAllFillUnits

Description
Definition
emptyAllFillUnits()
Code
1138function FillUnit:emptyAllFillUnits(ignoreDeleteOnEmptyFlag)
1139 local spec = self.spec_fillUnit
1140 local oldRemoveOnEmpty = spec.removeVehicleIfEmpty
1141 if ignoreDeleteOnEmptyFlag then
1142 spec.removeVehicleIfEmpty = false
1143 end
1144
1145 for k, _ in ipairs(self:getFillUnits()) do
1146 local fillTypeIndex = self:getFillUnitFillType(k)
1147 self:addFillUnitFillLevel(self:getOwnerFarmId(), k, -math.huge, fillTypeIndex, ToolType.UNDEFINED, nil)
1148 end
1149
1150 spec.removeVehicleIfEmpty = oldRemoveOnEmpty
1151end

getAdditionalComponentMass

Description
Definition
getAdditionalComponentMass()
Code
2165function FillUnit:getAdditionalComponentMass(superFunc, component)
2166 local additionalMass = superFunc(self, component)
2167 local spec = self.spec_fillUnit
2168
2169 for _, fillUnit in ipairs(spec.fillUnits) do
2170 if fillUnit.updateMass and fillUnit.fillMassNode == component.node and fillUnit.fillType ~= nil and fillUnit.fillType ~= FillType.UNKNOWN then
2171 local desc = g_fillTypeManager:getFillTypeByIndex(fillUnit.fillType)
2172 local mass = fillUnit.fillLevel * desc.massPerLiter
2173 additionalMass = additionalMass + mass
2174 end
2175 end
2176
2177 return additionalMass
2178end

getAlarmTriggerIsActive

Description
Definition
getAlarmTriggerIsActive()
Code
1076function FillUnit:getAlarmTriggerIsActive(alarmTrigger)
1077 local ret = false
1078
1079 local fillLevelPct = alarmTrigger.fillUnit.fillLevel / alarmTrigger.fillUnit.capacity
1080 if fillLevelPct >= alarmTrigger.minFillLevel and fillLevelPct <= alarmTrigger.maxFillLevel then
1081 ret = true
1082 end
1083
1084 return ret
1085end

getAllowLoadTriggerActivation

Description
Definition
getAllowLoadTriggerActivation()
Code
1165function FillUnit:getAllowLoadTriggerActivation(rootVehicle)
1166 if self.rootVehicle == g_currentMission.controlledVehicle then
1167 return true
1168 end
1169
1170 return false
1171end

getCanBeTurnedOn

Description
Definition
getCanBeTurnedOn()
Code
2335function FillUnit:getCanBeTurnedOn(superFunc)
2336 local spec = self.spec_fillUnit
2337
2338 for _, alarmTrigger in pairs(spec.activeAlarmTriggers) do
2339 if alarmTrigger.turnOffInTrigger then
2340 return false
2341 end
2342 end
2343
2344 return superFunc(self)
2345end

getCapacityFromXml

Description
Definition
getCapacityFromXml()
Code
2605function FillUnit.getCapacityFromXml(xmlFile)
2606 local rootName = xmlFile:getRootName()
2607 local maxCapacity = 0
2608
2609 xmlFile:iterate(rootName..".fillUnit.fillUnitConfigurations.fillUnitConfiguration",function(_, key)
2610 xmlFile:iterate(key..".fillUnits.fillUnit", function(_, fillUnitKey)
2611 maxCapacity = math.max(maxCapacity, xmlFile:getValue(fillUnitKey .. "#capacity") or 0)
2612 end)
2613 end)
2614
2615 return maxCapacity
2616end

getDoConsumePtoPower

Description
Definition
getDoConsumePtoPower()
Code
2321function FillUnit:getDoConsumePtoPower(superFunc)
2322 local fillTrigger = self.spec_fillUnit.fillTrigger
2323 return superFunc(self) or (fillTrigger.isFilling and fillTrigger.consumePtoPower)
2324end

getDrawFirstFillText

Description
Definition
getDrawFirstFillText()
Code
761function FillUnit:getDrawFirstFillText()
762 return false
763end

getFillLevelInformation

Description
Get fill level information
Definition
getFillLevelInformation(table fillLevelInformations)
Arguments
tablefillLevelInformationsfill level informations
Code
2219function FillUnit:getFillLevelInformation(superFunc, display)
2220 superFunc(self, display)
2221
2222 local spec = self.spec_fillUnit
2223 for i=1, #spec.fillUnits do
2224 local fillUnit = spec.fillUnits[i]
2225 if fillUnit.capacity > 0 and fillUnit.showOnHud then
2226 local fillType = fillUnit.fillType
2227
2228 -- if we only support one fill type and are empty we show the fill type
2229 if fillType == FillType.UNKNOWN then
2230 if table.size(fillUnit.supportedFillTypes) == 1 then
2231 fillType = next(fillUnit.supportedFillTypes)
2232 end
2233 end
2234
2235 if fillUnit.fillTypeToDisplay ~= FillType.UNKNOWN then
2236 fillType = fillUnit.fillTypeToDisplay
2237 end
2238
2239 local fillLevel = fillUnit.fillLevel
2240 if fillUnit.fillLevelToDisplay ~= nil then
2241 fillLevel = fillUnit.fillLevelToDisplay
2242 end
2243
2244 -- child and parent units will be merged together as display if one of them has a valid fill type and another an unknown fill type
2245 -- capacity is used from the parent one
2246 local capacity = fillUnit.capacity
2247 if fillUnit.parentUnitOnHud ~= nil then
2248 if fillType == FillType.UNKNOWN then
2249 fillType = spec.fillUnits[fillUnit.parentUnitOnHud].fillType
2250 end
2251 capacity = 0
2252 elseif fillUnit.childUnitOnHud ~= nil then
2253 if fillType == FillType.UNKNOWN then
2254 fillType = spec.fillUnits[fillUnit.childUnitOnHud].fillType
2255 end
2256 end
2257
2258 local maxReached = not fillUnit.ignoreFillLimit and g_currentMission.missionInfo.trailerFillLimit and self:getMaxComponentMassReached()
2259 display:addFillLevel(fillType, fillLevel, capacity, fillLevel > 0 and fillUnit.uiPrecision or 0, maxReached)
2260 end
2261 end
2262end

getFillTypeChangeThreshold

Description
Definition
getFillTypeChangeThreshold()
Code
972function FillUnit:getFillTypeChangeThreshold(fillUnitIndex)
973 if fillUnitIndex == nil then
974 return self.spec_fillUnit.fillTypeChangeThreshold
975 else
976 local capacity = self:getFillUnitCapacity(fillUnitIndex) or 1
977 return capacity * self.spec_fillUnit.fillTypeChangeThreshold
978 end
979end

getFillTypeNamesFromXML

Description
Definition
getFillTypeNamesFromXML()
Code
2698function FillUnit.getFillTypeNamesFromXML(xmlFile)
2699 local fillTypeNames = nil
2700 local fillTypeCategoryNames = nil
2701 local rootName = xmlFile:getRootName()
2702
2703 xmlFile:iterate(rootName..".fillUnit.fillUnitConfigurations.fillUnitConfiguration",function(_, key)
2704 xmlFile:iterate(key..".fillUnits.fillUnit", function(_, fillUnitKey)
2705 local capacity = xmlFile:getValue(fillUnitKey.."#capacity")
2706 if capacity == nil or capacity > 0 then
2707 local currentFillTypes = xmlFile:getValue(fillUnitKey .. "#fillTypes")
2708 if currentFillTypes ~= nil then
2709 if fillTypeNames == nil then
2710 fillTypeNames = currentFillTypes
2711 else
2712 fillTypeNames = fillTypeNames .. " " .. currentFillTypes
2713 end
2714 end
2715
2716 local currentFillTypeCategories = xmlFile:getValue(fillUnitKey .. "#fillTypeCategories")
2717 if currentFillTypeCategories ~= nil then
2718 if fillTypeCategoryNames == nil then
2719 fillTypeCategoryNames = currentFillTypeCategories
2720 else
2721 fillTypeCategoryNames = fillTypeCategoryNames .. " " .. currentFillTypeCategories
2722 end
2723 end
2724 end
2725 end)
2726 end)
2727
2728 return {fillTypeNames=fillTypeNames, fillTypeCategoryNames=fillTypeCategoryNames}
2729end

getFillUnitAllowsFillType

Description
Definition
getFillUnitAllowsFillType()
Code
956function FillUnit:getFillUnitAllowsFillType(fillUnitIndex, fillType)
957 local spec = self.spec_fillUnit
958 if spec.fillUnits[fillUnitIndex] ~= nil then
959 if self:getFillUnitSupportsFillType(fillUnitIndex, fillType) then
960 if fillType == spec.fillUnits[fillUnitIndex].fillType then
961 return true
962 else
963 return (spec.fillUnits[fillUnitIndex].fillLevel / math.max(spec.fillUnits[fillUnitIndex].capacity, 0.0001)) <= self:getFillTypeChangeThreshold()
964 end
965 end
966 end
967 return false
968end

getFillUnitAutoAimTargetNode

Description
Definition
getFillUnitAutoAimTargetNode()
Code
899function FillUnit:getFillUnitAutoAimTargetNode(fillUnitIndex)
900 local spec = self.spec_fillUnit
901 if spec.fillUnits[fillUnitIndex] ~= nil then
902 return spec.fillUnits[fillUnitIndex].autoAimTarget.node
903 end
904 return nil
905end

getFillUnitByIndex

Description
Definition
getFillUnitByIndex()
Code
774function FillUnit:getFillUnitByIndex(fillUnitIndex)
775 local spec = self.spec_fillUnit
776 if self:getFillUnitExists(fillUnitIndex) then
777 return spec.fillUnits[fillUnitIndex]
778 end
779 return nil
780end

getFillUnitCapacity

Description
Definition
getFillUnitCapacity()
Code
791function FillUnit:getFillUnitCapacity(fillUnitIndex)
792 local spec = self.spec_fillUnit
793 if spec.fillUnits[fillUnitIndex] ~= nil then
794 return spec.fillUnits[fillUnitIndex].capacity
795 end
796 return nil
797end

getFillUnitExactFillRootNode

Description
Definition
getFillUnitExactFillRootNode()
Code
879function FillUnit:getFillUnitExactFillRootNode(fillUnitIndex)
880 local spec = self.spec_fillUnit
881 if spec.fillUnits[fillUnitIndex] ~= nil then
882 return spec.fillUnits[fillUnitIndex].exactFillRootNode
883 end
884 return nil
885end

getFillUnitExists

Description
Definition
getFillUnitExists()
Code
784function FillUnit:getFillUnitExists(fillUnitIndex)
785 local spec = self.spec_fillUnit
786 return fillUnitIndex ~= nil and spec.fillUnits[fillUnitIndex] ~= nil
787end

getFillUnitExtraDistanceFromNode

Description
Definition
getFillUnitExtraDistanceFromNode()
Code
1124function FillUnit:getFillUnitExtraDistanceFromNode(node)
1125 local spec = self.spec_fillUnit
1126 return spec.exactFillRootNodeToExtraDistance[node] or 0
1127end

getFillUnitFillLevel

Description
Definition
getFillUnitFillLevel()
Code
829function FillUnit:getFillUnitFillLevel(fillUnitIndex)
830 local spec = self.spec_fillUnit
831 if spec.fillUnits[fillUnitIndex] ~= nil then
832 return spec.fillUnits[fillUnitIndex].fillLevel
833 end
834 return nil
835end

getFillUnitFillLevelPercentage

Description
Definition
getFillUnitFillLevelPercentage()
Code
839function FillUnit:getFillUnitFillLevelPercentage(fillUnitIndex)
840 local spec = self.spec_fillUnit
841 if spec.fillUnits[fillUnitIndex] ~= nil then
842 return spec.fillUnits[fillUnitIndex].fillLevel / spec.fillUnits[fillUnitIndex].capacity
843 end
844 return nil
845end

getFillUnitFillType

Description
Definition
getFillUnitFillType()
Code
849function FillUnit:getFillUnitFillType(fillUnitIndex)
850 local spec = self.spec_fillUnit
851 if spec.fillUnits[fillUnitIndex] ~= nil then
852 return spec.fillUnits[fillUnitIndex].fillType
853 end
854 return nil
855end

getFillUnitFirstSupportedFillType

Description
Definition
getFillUnitFirstSupportedFillType()
Code
869function FillUnit:getFillUnitFirstSupportedFillType(fillUnitIndex)
870 local spec = self.spec_fillUnit
871 if spec.fillUnits[fillUnitIndex] ~= nil then
872 return next(spec.fillUnits[fillUnitIndex].supportedFillTypes)
873 end
874 return nil
875end

getFillUnitForcedMaterialFillType

Description
Definition
getFillUnitForcedMaterialFillType()
Code
1057function FillUnit:getFillUnitForcedMaterialFillType(fillUnitIndex)
1058 local spec = self.spec_fillUnit
1059 if spec.fillUnits[fillUnitIndex] ~= nil then
1060 return spec.fillUnits[fillUnitIndex].forcedMaterialFillType
1061 end
1062
1063 return FillType.UNKNOWN
1064end

getFillUnitFreeCapacity

Description
getFillUnitFreeCapacity
Definition
getFillUnitFreeCapacity(Integer fillUnitIndex, Integer fillTypeIndex, Integer farmId)
Arguments
IntegerfillUnitIndex
IntegerfillTypeIndexcurrently ignored/unused
IntegerfarmIdcurrently ignored/unused
Code
804function FillUnit:getFillUnitFreeCapacity(fillUnitIndex, fillTypeIndex, farmId)
805 local spec = self.spec_fillUnit
806 local fillUnit = spec.fillUnits[fillUnitIndex]
807 if fillUnit ~= nil then
808 local freeCapacity = fillUnit.capacity - fillUnit.fillLevel
809
810 if not fillUnit.ignoreFillLimit then
811 if g_currentMission.missionInfo.trailerFillLimit and self:getMaxComponentMassReached() then
812 return 0
813 end
814 end
815
816 return freeCapacity
817 end
818 return nil
819end

getFillUnitFromNode

Description
Definition
getFillUnitFromNode()
Code
1131function FillUnit:getFillUnitFromNode(node)
1132 local spec = self.spec_fillUnit
1133 return spec.exactFillRootNodeToFillUnit[node]
1134end

getFillUnitIndexFromNode

Description
Definition
getFillUnitIndexFromNode()
Code
1112function FillUnit:getFillUnitIndexFromNode(node)
1113 local spec = self.spec_fillUnit
1114 local fillUnit = spec.exactFillRootNodeToFillUnit[node]
1115 if fillUnit ~= nil then
1116 return fillUnit.fillUnitIndex
1117 end
1118
1119 return nil
1120end

getFillUnitLastValidFillType

Description
Definition
getFillUnitLastValidFillType()
Code
859function FillUnit:getFillUnitLastValidFillType(fillUnitIndex)
860 local spec = self.spec_fillUnit
861 if spec.fillUnits[fillUnitIndex] ~= nil then
862 return spec.fillUnits[fillUnitIndex].lastValidFillType
863 end
864 return nil
865end

getFillUnitRootNode

Description
Definition
getFillUnitRootNode()
Code
889function FillUnit:getFillUnitRootNode(fillUnitIndex)
890 local spec = self.spec_fillUnit
891 if spec.fillUnits[fillUnitIndex] ~= nil then
892 return spec.fillUnits[fillUnitIndex].fillRootNode
893 end
894 return nil
895end

getFillUnits

Description
Definition
getFillUnits()
Code
767function FillUnit:getFillUnits()
768 local spec = self.spec_fillUnit
769 return spec.fillUnits
770end

getFillUnitSupportedFillTypes

Description
Definition
getFillUnitSupportedFillTypes()
Code
936function FillUnit:getFillUnitSupportedFillTypes(fillUnitIndex)
937 local spec = self.spec_fillUnit
938 if spec.fillUnits[fillUnitIndex] ~= nil then
939 return spec.fillUnits[fillUnitIndex].supportedFillTypes
940 end
941 return nil
942end

getFillUnitSupportedToolTypes

Description
Definition
getFillUnitSupportedToolTypes()
Code
946function FillUnit:getFillUnitSupportedToolTypes(fillUnitIndex)
947 local spec = self.spec_fillUnit
948 if spec.fillUnits[fillUnitIndex] ~= nil then
949 return spec.fillUnits[fillUnitIndex].supportedToolTypes
950 end
951 return nil
952end

getFillUnitSupportsFillType

Description
Definition
getFillUnitSupportsFillType()
Code
909function FillUnit:getFillUnitSupportsFillType(fillUnitIndex, fillType)
910 local spec = self.spec_fillUnit
911 if spec.fillUnits[fillUnitIndex] ~= nil then
912 return spec.fillUnits[fillUnitIndex].supportedFillTypes[fillType]
913 end
914 return false
915end

getFillUnitSupportsToolType

Description
Definition
getFillUnitSupportsToolType()
Code
919function FillUnit:getFillUnitSupportsToolType(fillUnitIndex, toolType)
920 local spec = self.spec_fillUnit
921 if spec.fillUnits[fillUnitIndex] ~= nil then
922 return spec.fillUnits[fillUnitIndex].supportedToolTypes[toolType]
923 end
924 return false
925end

getFillUnitSupportsToolTypeAndFillType

Description
Definition
getFillUnitSupportsToolTypeAndFillType()
Code
929function FillUnit:getFillUnitSupportsToolTypeAndFillType(fillUnitIndex, toolType, fillType)
930 return self:getFillUnitSupportsToolType(fillUnitIndex, toolType)
931 and self:getFillUnitSupportsFillType(fillUnitIndex, fillType)
932end

getFirstValidFillUnitToFill

Description
Definition
getFirstValidFillUnitToFill()
Code
983function FillUnit:getFirstValidFillUnitToFill(fillType, ignoreCapacity)
984 local spec = self.spec_fillUnit
985 for fillUnitIndex, _ in ipairs(spec.fillUnits) do
986 if self:getFillUnitAllowsFillType(fillUnitIndex, fillType) then
987 if self:getFillUnitFreeCapacity(fillUnitIndex) > 0 or (ignoreCapacity ~= nil and ignoreCapacity) then
988 return fillUnitIndex
989 end
990 end
991 end
992
993 return nil
994end

getIsFillAllowedFromFarm

Description
Definition
getIsFillAllowedFromFarm()
Code
823function FillUnit:getIsFillAllowedFromFarm(farmId)
824 return true
825end

getIsFillUnitActive

Description
Definition
getIsFillUnitActive()
Code
2157function FillUnit:getIsFillUnitActive(fillUnitIndex)
2158 return true
2159end

getIsFoldAllowed

Description
Definition
getIsFoldAllowed()
Code
2266function FillUnit:getIsFoldAllowed(superFunc, direction, onAiTurnOn)
2267 local spec = self.spec_fillUnit
2268 if not spec.allowFoldingWhileFilled then
2269 for fillUnitIndex, _ in ipairs(spec.fillUnits) do
2270 if self:getFillUnitFillLevel(fillUnitIndex) > spec.allowFoldingThreshold then
2271 return false, spec.texts.warningFoldingFilled
2272 end
2273 end
2274 end
2275
2276 return superFunc(self, direction, onAiTurnOn)
2277end

getIsLevelerPickupNodeActive

Description
Definition
getIsLevelerPickupNodeActive()
Code
2405function FillUnit:getIsLevelerPickupNodeActive(superFunc, levelerNode)
2406 local fillLevelPct = self:getFillUnitFillLevelPercentage(levelerNode.limitFillUnitIndex)
2407 if fillLevelPct < levelerNode.minFillLevel or fillLevelPct > levelerNode.maxFillLevel then
2408 return false
2409 end
2410
2411 return superFunc(self, levelerNode)
2412end

getIsMovingToolActive

Description
Definition
getIsMovingToolActive()
Code
2308function FillUnit:getIsMovingToolActive(superFunc, movingTool)
2309 if movingTool.fillUnitIndex ~= nil then
2310 local fillLevelPct = self:getFillUnitFillLevelPercentage(movingTool.fillUnitIndex)
2311 if fillLevelPct > movingTool.minFillLevel or fillLevelPct < movingTool.maxFillLevel then
2312 return false
2313 end
2314 end
2315
2316 return superFunc(self, movingTool)
2317end

getIsPowerTakeOffActive

Description
Definition
getIsPowerTakeOffActive()
Code
2328function FillUnit:getIsPowerTakeOffActive(superFunc)
2329 local fillTrigger = self.spec_fillUnit.fillTrigger
2330 return superFunc(self) or (fillTrigger.isFilling and fillTrigger.consumePtoPower)
2331end

getIsReadyForAutomatedTrainTravel

Description
Definition
getIsReadyForAutomatedTrainTravel()
Code
2281function FillUnit:getIsReadyForAutomatedTrainTravel(superFunc)
2282 local spec = self.spec_fillUnit
2283 for _, fillUnit in ipairs(spec.fillUnits) do
2284 if fillUnit.blocksAutomatedTrainTravel and fillUnit.fillLevel > 0 then
2285 return false
2286 end
2287 end
2288
2289 return superFunc(self)
2290end

getSpecValueCapacity

Description
Definition
getSpecValueCapacity()
Code
2516function FillUnit.getSpecValueCapacity(storeItem, realItem, configurations, saleItem, returnValues, returnRange)
2517 local configurationIndex = 1
2518 if realItem ~= nil and storeItem.configurations ~= nil and realItem.configurations["fillUnit"] ~= nil and storeItem.configurations["fillUnit"] ~= nil then
2519 configurationIndex = realItem.configurations["fillUnit"]
2520 elseif configurations ~= nil and storeItem.configurations ~= nil and configurations["fillUnit"] ~= nil and storeItem.configurations["fillUnit"] ~= nil then
2521 configurationIndex = configurations["fillUnit"]
2522 end
2523
2524 local minCapacity = 0
2525 local capacity = 0
2526 local unit = ""
2527
2528 local fillUnitConfigurations = storeItem.specs.capacity
2529 if fillUnitConfigurations ~= nil then
2530 if realItem ~= nil or (configurations ~= nil and saleItem ~= nil) then
2531 if fillUnitConfigurations[configurationIndex] ~= nil then
2532 for _, fillUnit in ipairs(fillUnitConfigurations[configurationIndex]) do
2533 if realItem ~= nil and realItem.getFillUnitCapacity ~= nil and fillUnit.fillUnitIndex ~= nil then
2534 local unitCapacity = realItem:getFillUnitCapacity(fillUnit.fillUnitIndex)
2535 if unitCapacity ~= 0 and unitCapacity ~= math.huge then
2536 if fillUnit.conversionFunc ~= nil then
2537 unitCapacity = fillUnit.conversionFunc(unitCapacity)
2538 end
2539 capacity = capacity + unitCapacity
2540 end
2541 else
2542 capacity = capacity + fillUnit.capacity
2543 end
2544
2545 unit = fillUnit.unit
2546 end
2547 minCapacity = capacity
2548 end
2549 else
2550 -- if no configuration index is given we use the max capacity the vehicle can have
2551 minCapacity = math.huge
2552 capacity = 0
2553 for _, configuration in ipairs(fillUnitConfigurations) do
2554 local configCapacity = 0
2555 for _, fillUnit in ipairs(configuration) do
2556 configCapacity = configCapacity + fillUnit.capacity
2557 unit = fillUnit.unit
2558 end
2559
2560 if configCapacity ~= 0 then
2561 minCapacity = math.min(minCapacity, configCapacity)
2562 capacity = math.max(capacity, configCapacity)
2563 end
2564 end
2565
2566 if minCapacity == capacity then
2567 capacity = minCapacity
2568 else
2569 if minCapacity ~= math.huge and capacity ~= 0 then
2570 if returnValues == nil or not returnValues then
2571 -- while allowed to return a string we return capacity range
2572 capacity = string.format("%s-%s", minCapacity, capacity)
2573 end
2574 end
2575 end
2576 end
2577 end
2578
2579 if type(capacity) == "number" and capacity == 0 then
2580 if returnValues == nil or not returnValues then
2581 return nil
2582 end
2583 end
2584
2585 if unit ~= "" then
2586 if unit:sub(1,6) == "$l10n_" then
2587 unit = unit:sub(7)
2588 end
2589 end
2590
2591 if returnValues == nil or not returnValues then
2592 return string.format(g_i18n:getText("shop_capacityValue"), capacity, g_i18n:getText(unit or "unit_literShort"))
2593 else
2594 if returnRange == true and capacity ~= minCapacity then
2595 return minCapacity, capacity, unit
2596 else
2597 return minCapacity, unit
2598 end
2599 end
2600end

getSpecValueFillTypes

Description
Definition
getSpecValueFillTypes()
Code
2733function FillUnit.getSpecValueFillTypes(storeItem, realItem, configurations)
2734 local specs = storeItem.specs.fillTypes
2735 if specs ~= nil then
2736 local configuration
2737 if configurations ~= nil then
2738 local configId = configurations["fillUnit"]
2739 configuration = specs.fillTypesByConfiguration[configId]
2740 end
2741
2742 local categoryNames = specs.categoryNames
2743 if configuration ~= nil then
2744 categoryNames = configuration.categoryNames or categoryNames
2745 end
2746
2747 local fillTypeNames = specs.fillTypeNames
2748 if configuration ~= nil then
2749 fillTypeNames = configuration.fillTypeNames or fillTypeNames
2750 end
2751
2752 if categoryNames ~= nil or fillTypeNames ~= nil then
2753 local fillTypes = {}
2754 if categoryNames ~= nil then
2755 g_fillTypeManager:getFillTypesByCategoryNames(categoryNames, nil, fillTypes)
2756 end
2757 if fillTypeNames ~= nil then
2758 g_fillTypeManager:getFillTypesByNames(fillTypeNames, nil, fillTypes)
2759 end
2760
2761 return fillTypes
2762 elseif specs.fruitTypeNames ~= nil then
2763 return g_fruitTypeManager:getFillTypesByFruitTypeNames(specs.fruitTypeNames, nil)
2764 elseif specs.fruitTypeCategoryNames ~= nil then
2765 if specs.useWindrowed then
2766 local fruitTypes = g_fruitTypeManager:getFruitTypesByCategoryNames(specs.fruitTypeCategoryNames, "Warning: Cutter has invalid fruitTypeCategory '%s'.")
2767 local windrowFillTypes = {}
2768
2769 for _, fruitType in pairs(fruitTypes) do
2770 table.insert(windrowFillTypes, g_fruitTypeManager:getWindrowFillTypeIndexByFruitTypeIndex(fruitType))
2771 end
2772
2773 return windrowFillTypes
2774 else
2775 return g_fruitTypeManager:getFillTypesByFruitTypeCategoryName(specs.fruitTypeCategoryNames, nil)
2776 end
2777 end
2778 end
2779 return nil
2780end

getSpecValueStartFillUnitMassByMassData

Description
Definition
getSpecValueStartFillUnitMassByMassData()
Code
2813function FillUnit.getSpecValueStartFillUnitMassByMassData(fillUnitMassData)
2814 local mass = 0
2815 for _, massData in pairs(fillUnitMassData) do
2816 local fillType
2817 if massData.fillTypeCategories ~= nil then
2818 local fillTypes = g_fillTypeManager:getFillTypesByCategoryNames(massData.fillTypeCategories)
2819 fillType = fillTypes[1]
2820 elseif massData.fillTypes ~= nil then
2821 local fillTypes = g_fillTypeManager:getFillTypesByNames(massData.fillTypes)
2822 fillType = fillTypes[1]
2823 elseif massData.fillType ~= nil then
2824 fillType = g_fillTypeManager:getFillTypeIndexByName(massData.fillType)
2825 end
2826
2827 if fillType ~= nil then
2828 local fillTypeDesc = g_fillTypeManager:getFillTypeByIndex(fillType)
2829 mass = mass + massData.capacity * fillTypeDesc.massPerLiter
2830 end
2831 end
2832
2833 return mass
2834end

initSpecialization

Description
Definition
initSpecialization()
Code
32function FillUnit.initSpecialization()
33 Vehicle.registerStateChange("FILLTYPE_CHANGE")
34
35 g_configurationManager:addConfigurationType("fillUnit", g_i18n:getText("configuration_fillUnit"), "fillUnit", nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
36
37 g_storeManager:addSpecType("capacity", "shopListAttributeIconCapacity", FillUnit.loadSpecValueCapacity, FillUnit.getSpecValueCapacity, "vehicle", {"fillUnit"})
38 g_storeManager:addSpecType("fillTypes", "shopListAttributeIconFillTypes", FillUnit.loadSpecValueFillTypes, FillUnit.getSpecValueFillTypes, "vehicle", {"fillUnit"})
39
40 local schema = Vehicle.xmlSchema
41 schema:setXMLSpecializationType("FillUnit")
42
43 schema:register(XMLValueType.STRING, "vehicle.storeData.specs.fillTypes", "Fill types")
44 schema:register(XMLValueType.STRING, "vehicle.storeData.specs.fillTypeCategories", "Fill type categories")
45 schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.capacity", "Capacity")
46 FillUnit.registerUnitDisplaySchema(schema, "vehicle.storeData.specs.capacity")
47
48 schema:register(XMLValueType.BOOL, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits#removeVehicleIfEmpty", "Remove vehicle if unit empty", false)
49 schema:register(XMLValueType.TIME, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits#removeVehicleDelay", "Delay for vehicle removal (e.g. can be used while sounds are still playing)", 0)
50 schema:register(XMLValueType.BOOL, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits#allowFoldingWhileFilled", "Allow folding while filled", true)
51 schema:register(XMLValueType.FLOAT, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits#allowFoldingThreshold", "Allow folding threshold", 0.0001)
52 schema:register(XMLValueType.FLOAT, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits#fillTypeChangeThreshold", "Fill type overwrite threshold", 0.05)
53
54 schema:register(XMLValueType.FLOAT, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits.fillTrigger#litersPerSecond", "Fill liters per second", 200)
55 schema:register(XMLValueType.BOOL, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits.fillTrigger#consumePtoPower", "Consume pto power while filling", false)
56
57 local fillUnitPath = FillUnit.FILL_UNIT_XML_KEY
58
59 schema:register(XMLValueType.FLOAT, fillUnitPath .. "#capacity", "Capacity", "unlimited")
60 schema:register(XMLValueType.BOOL, fillUnitPath .. "#updateMass", "Update vehicle mass while fill level changes", true)
61 schema:register(XMLValueType.BOOL, fillUnitPath .. "#canBeUnloaded", "Can be unloaded", true)
62
63 FillUnit.registerUnitDisplaySchema(schema, fillUnitPath)
64 schema:register(XMLValueType.BOOL, fillUnitPath .. "#showCapacityInShop", "Show capacity in shop", true)
65 schema:register(XMLValueType.BOOL, fillUnitPath .. "#showInShop", "Show in shop", true)
66
67 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".exactFillRootNode#node", "Exact fill root node")
68 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".exactFillRootNode#extraEffectDistance", "Exact fill root node extra distance", 0)
69
70 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".autoAimTargetNode#node", "Auto aim target node")
71 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".autoAimTargetNode#startZ", "Start Z translation")
72 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".autoAimTargetNode#endZ", "End Z translation")
73 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".autoAimTargetNode#startPercentage", "Start move percentage")
74 schema:register(XMLValueType.BOOL, fillUnitPath .. ".autoAimTargetNode#invert", "Invert Z movement")
75
76 schema:register(XMLValueType.STRING, fillUnitPath .. "#fillTypeCategories", "Supported fill type categories")
77 schema:register(XMLValueType.STRING, fillUnitPath .. "#fillTypes", "Supported fill types")
78
79 schema:register(XMLValueType.FLOAT, fillUnitPath .. "#startFillLevel", "Start fill level")
80 schema:register(XMLValueType.STRING, fillUnitPath .. "#startFillType", "Start fill type")
81
82 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".fillRootNode#node", "Fill root node", "first component")
83 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".fillMassNode#node", "Fill root node", "first component")
84 schema:register(XMLValueType.BOOL, fillUnitPath .. "#updateFillLevelMass", "Update fill level mass", true)
85 schema:register(XMLValueType.BOOL, fillUnitPath .. "#ignoreFillLimit", "Ignores limiting of filling if the max mass is reached (if the settings is turned on)", false)
86
87 schema:register(XMLValueType.BOOL, fillUnitPath .. "#synchronizeFillLevel", "Synchronize fill level", true)
88 schema:register(XMLValueType.BOOL, fillUnitPath .. "#synchronizeFullFillLevel", "Synchronize fill level as 32bit float instead of percentage with max. 16 bits", false)
89 schema:register(XMLValueType.INT, fillUnitPath .. "#synchronizationNumBits", "Synchronization bits")
90
91 schema:register(XMLValueType.BOOL, fillUnitPath .. "#showOnHud", "Show on HUD", true)
92 schema:register(XMLValueType.BOOL, fillUnitPath .. "#showOnInfoHud", "Show on Info HUD", true)
93 schema:register(XMLValueType.INT, fillUnitPath .. "#uiPrecision", "Precision in UI display", 0)
94 schema:register(XMLValueType.BOOL, fillUnitPath .. "#blocksAutomatedTrainTravel", "Block automated train travel if not empty", false)
95
96 schema:register(XMLValueType.STRING, fillUnitPath .. "#fillAnimation", "Fill animation name")
97 schema:register(XMLValueType.FLOAT, fillUnitPath .. "#fillAnimationLoadTime", "Fill animation load time")
98 schema:register(XMLValueType.FLOAT, fillUnitPath .. "#fillAnimationEmptyTime", "Fill animation empty time")
99
100 schema:register(XMLValueType.STRING, fillUnitPath .. ".fillLevelAnimation#name", "Fill level animation name (Animation time is set depending on fill level percentage)")
101 schema:register(XMLValueType.BOOL, fillUnitPath .. ".fillLevelAnimation#resetOnEmpty", "Update animation when fill level reaches zero", true)
102
103 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".alarmTriggers.alarmTrigger(?)#minFillLevel", "Fill animation empty time")
104 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".alarmTriggers.alarmTrigger(?)#maxFillLevel", "Fill animation empty time")
105 schema:register(XMLValueType.BOOL, fillUnitPath .. ".alarmTriggers.alarmTrigger(?)#needsTurnOn", "Needs turn on", false)
106 schema:register(XMLValueType.BOOL, fillUnitPath .. ".alarmTriggers.alarmTrigger(?)#turnOffInTrigger", "Turn off in trigger", false)
107 SoundManager.registerSampleXMLPaths(schema, fillUnitPath .. ".alarmTriggers.alarmTrigger(?)", "alarmSound")
108
109 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".measurementNodes.measurementNode(?)#node", "Measurement node")
110
111 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".fillPlane.node(?)#node", "Fill plane node")
112 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".fillPlane.node(?).key(?)#time", "Key time")
113 schema:register(XMLValueType.VECTOR_TRANS, fillUnitPath .. ".fillPlane.node(?).key(?)#translation", "Translation")
114 schema:register(XMLValueType.FLOAT, fillUnitPath .. ".fillPlane.node(?).key(?)#y", "Y Translation")
115 schema:register(XMLValueType.VECTOR_ROT, fillUnitPath .. ".fillPlane.node(?).key(?)#rotation", "Rotation")
116 schema:register(XMLValueType.VECTOR_SCALE, fillUnitPath .. ".fillPlane.node(?).key(?)#scale", "Scale")
117 schema:register(XMLValueType.VECTOR_2, fillUnitPath .. ".fillPlane.node(?)#minMaxY", "Min. and max. Y translation")
118 schema:register(XMLValueType.BOOL, fillUnitPath .. ".fillPlane.node(?)#alwaysVisible", "Is always visible", false)
119 schema:register(XMLValueType.STRING, fillUnitPath .. ".fillPlane#defaultFillType", "Default fill type name")
120
121 schema:register(XMLValueType.STRING, fillUnitPath .. ".fillTypeMaterials.material(?)#fillType", "Fill type name")
122 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".fillTypeMaterials.material(?)#node", "Node which receives material")
123 schema:register(XMLValueType.NODE_INDEX, fillUnitPath .. ".fillTypeMaterials.material(?)#refNode", "Node which provides material")
124
125 EffectManager.registerEffectXMLPaths(schema, fillUnitPath .. ".fillEffect")
126 AnimationManager.registerAnimationNodesXMLPaths(schema, fillUnitPath .. ".animationNodes")
127
128 Dashboard.registerDashboardXMLPaths(schema, fillUnitPath, "fillLevel | fillLevelPct | fillLevelWarning")
129 Dashboard.registerDashboardWarningXMLPaths(schema, fillUnitPath)
130
131 schema:register(XMLValueType.NODE_INDEX, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits.unloading(?)#node", "Unloading node")
132 schema:register(XMLValueType.FLOAT, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits.unloading(?)#width", "Unloading width", 15)
133 schema:register(XMLValueType.VECTOR_TRANS, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits.unloading(?)#offset", "Unloading offset", "0 0 0")
134
135 EffectManager.registerEffectXMLPaths(schema, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits.fillEffect")
136 AnimationManager.registerAnimationNodesXMLPaths(schema, FillUnit.FILL_UNIT_CONFIG_XML_KEY .. ".fillUnits.animationNodes")
137 SoundManager.registerSampleXMLPaths(schema, "vehicle.fillUnit.sounds", "fill")
138
139 ObjectChangeUtil.registerObjectChangeXMLPaths(schema, FillUnit.FILL_UNIT_CONFIG_XML_KEY)
140
141 schema:register(XMLValueType.INT, Leveler.LEVELER_NODE_XML_KEY .. "#fillUnitIndex", "Reference fill unit index", 1)
142 schema:register(XMLValueType.FLOAT, Leveler.LEVELER_NODE_XML_KEY .. "#minFillLevel", "Min. fill level to activate leveler node (pct between 0 and 1)", 0)
143 schema:register(XMLValueType.FLOAT, Leveler.LEVELER_NODE_XML_KEY .. "#maxFillLevel", "Max. fill level to activate leveler node (pct between 0 and 1)", 1)
144
145 schema:setXMLSpecializationType()
146
147 local schemaSavegame = Vehicle.xmlSchemaSavegame
148 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).fillUnit.unit(?)#index", "Fill Unit index")
149 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?).fillUnit.unit(?)#fillType", "Fill type")
150 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?).fillUnit.unit(?)#fillLevel", "Fill level")
151end

loadAlarmTrigger

Description
Definition
loadAlarmTrigger()
Code
1749function FillUnit:loadAlarmTrigger(xmlFile, key, alarmTrigger, fillUnit)
1750 alarmTrigger.fillUnit = fillUnit
1751 alarmTrigger.isActive = false
1752
1753 local success = true
1754 alarmTrigger.minFillLevel = xmlFile:getValue(key .. "#minFillLevel")
1755 if alarmTrigger.minFillLevel == nil then
1756 Logging.xmlWarning(self.xmlFile, "Missing 'minFillLevel' for alarmTrigger '%s'", key)
1757 success = false
1758 end
1759
1760 alarmTrigger.maxFillLevel = xmlFile:getValue(key .. "#maxFillLevel")
1761 if alarmTrigger.maxFillLevel == nil then
1762 Logging.xmlWarning(self.xmlFile, "Missing 'maxFillLevel' for alarmTrigger '%s'", key)
1763 success = false
1764 end
1765
1766 alarmTrigger.sample = g_soundManager:loadSampleFromXML(xmlFile, key, "alarmSound", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
1767
1768 return success
1769end

loadFillPlane

Description
Definition
loadFillPlane()
Code
1815function FillUnit:loadFillPlane(xmlFile, key, fillPlane, fillUnit)
1816 XMLUtil.checkDeprecatedXMLElements(xmlFile, key.."#fillType", "Material is dynamically assigned to the nodes")
1817
1818 if not xmlFile:hasProperty(key) then
1819 return false
1820 end
1821
1822 fillPlane.nodes = {}
1823 local i = 0
1824 while true do
1825 local nodeKey = string.format("%s.node(%d)", key, i)
1826 if not xmlFile:hasProperty(nodeKey) then
1827 break
1828 end
1829
1830 XMLUtil.checkDeprecatedXMLElements(xmlFile, nodeKey.."#index", nodeKey.."#node") -- FS17 to FS19
1831
1832 local node = xmlFile:getValue(nodeKey.."#node", nil, self.components, self.i3dMappings)
1833 if node ~= nil then
1834 local defaultX, defaultY, defaultZ = getTranslation(node)
1835 local defaultRX, defaultRY, defaultRZ = getRotation(node)
1836
1837 local animCurve = AnimCurve.new(linearInterpolatorTransRotScale)
1838 local j = 0
1839 while true do
1840 local animKey = string.format("%s.key(%d)", nodeKey, j)
1841 if not xmlFile:hasProperty(animKey) then
1842 break
1843 end
1844
1845 local keyTime = xmlFile:getValue(animKey.."#time")
1846 if keyTime == nil then
1847 break
1848 end
1849
1850 local x, y, z = xmlFile:getValue(animKey.."#translation")
1851 if y == nil then
1852 y = xmlFile:getValue(animKey.."#y")
1853 end
1854 x = x or defaultX
1855 y = y or defaultY
1856 z = z or defaultZ
1857
1858 local rx, ry, rz = xmlFile:getValue(animKey.."#rotation")
1859 rx = rx or defaultRX
1860 ry = ry or defaultRY
1861 rz = rz or defaultRZ
1862
1863 local sx, sy, sz = xmlFile:getValue(animKey.."#scale")
1864 sx = sx or 1
1865 sy = sy or 1
1866 sz = sz or 1
1867
1868 animCurve:addKeyframe({x=x, y=y, z=z, rx=rx, ry=ry, rz=rz, sx=sx, sy=sy, sz=sz, time = keyTime})
1869 j = j + 1
1870 end
1871
1872 if j == 0 then
1873 local minY, maxY = xmlFile:getValue(nodeKey.."#minMaxY")
1874 minY = minY or defaultY
1875 maxY = maxY or defaultY
1876 animCurve:addKeyframe({defaultX, minY, defaultZ, defaultRX, defaultRY, defaultRZ, 1, 1, 1, time = 0})
1877 animCurve:addKeyframe({defaultX, maxY, defaultZ, defaultRX, defaultRY, defaultRZ, 1, 1, 1, time = 1})
1878 end
1879
1880 local alwaysVisible = xmlFile:getValue(nodeKey.."#alwaysVisible", false)
1881 setVisibility(node, alwaysVisible)
1882
1883 table.insert(fillPlane.nodes, {node=node, animCurve=animCurve, alwaysVisible=alwaysVisible})
1884 end
1885 i = i + 1
1886 end
1887
1888 fillPlane.forcedFillType = nil
1889
1890 local defaultFillTypeStr = xmlFile:getValue(key .. "#defaultFillType")
1891 if defaultFillTypeStr ~= nil then
1892 local defaultFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(defaultFillTypeStr)
1893 if defaultFillTypeIndex == nil then
1894 Logging.xmlWarning(self.xmlFile, "Invalid defaultFillType '%s' for '%s'!", tostring(defaultFillTypeStr), key)
1895 return false
1896 else
1897 fillPlane.defaultFillType = defaultFillTypeIndex
1898 end
1899 else
1900 fillPlane.defaultFillType = next(fillUnit.supportedFillTypes)
1901 end
1902
1903 return true
1904end

loadFillTypeMaterials

Description
Definition
loadFillTypeMaterials()
Code
1961function FillUnit:loadFillTypeMaterials(xmlFile, key)
1962 local fillTypeMaterials = {}
1963 xmlFile:iterate(key .. ".fillTypeMaterials.material", function(_, materialKey)
1964 local fillTypeName = xmlFile:getValue(materialKey .. "#fillType")
1965 if fillTypeName ~= nil then
1966 local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeName)
1967 if fillTypeIndex ~= nil then
1968 local node = xmlFile:getValue(materialKey .. "#node", nil, self.components, self.i3dMappings)
1969 local refNode = xmlFile:getValue(materialKey .. "#refNode", nil, self.components, self.i3dMappings)
1970 if node ~= nil and refNode ~= nil then
1971 local fillTypeMaterial = {}
1972 fillTypeMaterial.fillTypeIndex = fillTypeIndex
1973 fillTypeMaterial.node = node
1974 fillTypeMaterial.refNode = refNode
1975 table.insert(fillTypeMaterials, fillTypeMaterial)
1976 else
1977 Logging.xmlWarning(xmlFile, "Missing node or ref node in '%s'", materialKey)
1978 end
1979 else
1980 Logging.xmlWarning(xmlFile, "Unknown fill type '%s' in '%s'", fillTypeName, materialKey)
1981 end
1982 else
1983 Logging.xmlWarning(xmlFile, "Missing fill type in '%s'", materialKey)
1984 end
1985 end)
1986
1987 return fillTypeMaterials
1988end

loadFillUnitFromXML

Description
Definition
loadFillUnitFromXML()
Code
1536function FillUnit:loadFillUnitFromXML(xmlFile, key, entry, index)
1537 local spec = self.spec_fillUnit
1538
1539 entry.fillUnitIndex = index
1540 entry.capacity = xmlFile:getValue(key .. "#capacity", math.huge)
1541 entry.defaultCapacity = entry.capacity
1542 entry.updateMass = xmlFile:getValue(key .. "#updateMass", true)
1543 entry.canBeUnloaded = xmlFile:getValue(key .. "#canBeUnloaded", true)
1544 entry.needsSaving = true
1545
1546 entry.fillLevel = 0
1547 entry.fillLevelSent = 0
1548
1549 entry.fillType = FillType.UNKNOWN
1550 entry.fillTypeSent = FillType.UNKNOWN
1551 entry.fillTypeToDisplay = FillType.UNKNOWN
1552 entry.fillLevelToDisplay = nil
1553
1554 entry.lastValidFillType = FillType.UNKNOWN
1555 entry.lastValidFillTypeSent = FillType.UNKNOWN
1556
1557 if xmlFile:hasProperty(key .. ".exactFillRootNode") then
1558 XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. ".exactFillRootNode#index", key .. ".exactFillRootNode#node") --FS17 to FS19
1559
1560 entry.exactFillRootNode = xmlFile:getValue(key .. ".exactFillRootNode#node", nil, self.components, self.i3dMappings)
1561 if entry.exactFillRootNode ~= nil then
1562 if not CollisionFlag.getHasFlagSet(entry.exactFillRootNode, CollisionFlag.FILLABLE) then
1563 Logging.xmlWarning(self.xmlFile, "Missing collision mask bit '%d'. Please add this bit to exact fill root node '%s' in '%s'", CollisionFlag.getBit(CollisionFlag.FILLABLE), getName(entry.exactFillRootNode), key)
1564 return false
1565 end
1566
1567 spec.exactFillRootNodeToFillUnit[entry.exactFillRootNode] = entry
1568 spec.exactFillRootNodeToExtraDistance[entry.exactFillRootNode] = xmlFile:getValue(key .. ".exactFillRootNode#extraEffectDistance", 0)
1569 spec.hasExactFillRootNodes = true
1570 else
1571 Logging.xmlWarning(self.xmlFile, "ExactFillRootNode not found for fillUnit '%s'!", key)
1572 end
1573 end
1574
1575 XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. ".autoAimTargetNode#index", key .. ".autoAimTargetNode#node") --FS17 to FS19
1576
1577 entry.autoAimTarget = {}
1578 entry.autoAimTarget.node = xmlFile:getValue(key .. ".autoAimTargetNode#node", nil, self.components, self.i3dMappings)
1579 if entry.autoAimTarget.node ~= nil then
1580 entry.autoAimTarget.baseTrans = {getTranslation(entry.autoAimTarget.node)}
1581 entry.autoAimTarget.startZ = xmlFile:getValue( key ..".autoAimTargetNode#startZ")
1582 entry.autoAimTarget.endZ = xmlFile:getValue( key ..".autoAimTargetNode#endZ")
1583 entry.autoAimTarget.startPercentage = xmlFile:getValue( key ..".autoAimTargetNode#startPercentage", 25) / 100
1584 entry.autoAimTarget.invert = xmlFile:getValue( key ..".autoAimTargetNode#invert", false)
1585 if entry.autoAimTarget.startZ ~= nil and entry.autoAimTarget.endZ ~= nil then
1586 local startZ = entry.autoAimTarget.startZ
1587 if entry.autoAimTarget.invert then
1588 startZ = entry.autoAimTarget.endZ
1589 end
1590
1591 setTranslation(entry.autoAimTarget.node, entry.autoAimTarget.baseTrans[1], entry.autoAimTarget.baseTrans[2], startZ)
1592 end
1593 end
1594
1595 entry.supportedFillTypes = {}
1596 local fillTypes
1597 local fillTypeCategories = xmlFile:getValue(key .. "#fillTypeCategories")
1598 local fillTypeNames = xmlFile:getValue(key .. "#fillTypes")
1599 if fillTypeCategories ~= nil and fillTypeNames == nil then
1600 fillTypes = g_fillTypeManager:getFillTypesByCategoryNames(fillTypeCategories, "Warning: '"..self.configFileName.. "' has invalid fillTypeCategory '%s'.")
1601 elseif fillTypeCategories == nil and fillTypeNames ~= nil then
1602 fillTypes = g_fillTypeManager:getFillTypesByNames(fillTypeNames, "Warning: '"..self.configFileName.. "' has invalid fillType '%s'.")
1603 else
1604 Logging.xmlWarning(self.xmlFile, "Missing 'fillTypeCategories' or 'fillTypes' for fillUnit '%s'", key)
1605 return false
1606 end
1607
1608 if fillTypes ~= nil then
1609 for _,fillType in pairs(fillTypes) do
1610 entry.supportedFillTypes[fillType] = true
1611 end
1612 end
1613
1614 entry.supportedToolTypes = {}
1615 for i=1, g_toolTypeManager:getNumberOfToolTypes() do
1616 entry.supportedToolTypes[i] = true
1617 end
1618
1619 local startFillLevel = xmlFile:getValue(key .. "#startFillLevel")
1620 local startFillTypeStr = xmlFile:getValue(key .. "#startFillType")
1621 if startFillTypeStr ~= nil then
1622 local startFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(startFillTypeStr)
1623 if startFillTypeIndex ~= nil then
1624 entry.startFillLevel = startFillLevel
1625 entry.startFillTypeIndex = startFillTypeIndex
1626 end
1627 end
1628
1629 entry.fillRootNode = xmlFile:getValue(key .. ".fillRootNode#node", nil, self.components, self.i3dMappings)
1630 if entry.fillRootNode == nil then
1631 entry.fillRootNode = self.components[1].node
1632 end
1633
1634 entry.fillMassNode = xmlFile:getValue(key .. ".fillMassNode#node", nil, self.components, self.i3dMappings)
1635 local updateFillLevelMass = xmlFile:getValue(key .. "#updateFillLevelMass", true)
1636 if entry.fillMassNode == nil and updateFillLevelMass then
1637 entry.fillMassNode = self.components[1].node
1638 end
1639
1640 entry.ignoreFillLimit = xmlFile:getValue(key .. "#ignoreFillLimit", false)
1641
1642 -- mp sync info
1643 entry.synchronizeFillLevel = xmlFile:getValue(key .. "#synchronizeFillLevel", true)
1644 entry.synchronizeFullFillLevel = xmlFile:getValue(key .. "#synchronizeFullFillLevel", false)
1645
1646 local defaultBits = 16
1647 for startCapacity, bits in pairs(FillUnit.CAPACITY_TO_NETWORK_BITS) do
1648 if entry.capacity >= startCapacity then
1649 defaultBits = bits
1650 end
1651 end
1652
1653 entry.synchronizationNumBits = xmlFile:getValue(key .. "#synchronizationNumBits", defaultBits)
1654
1655 entry.showOnHud = xmlFile:getValue(key .. "#showOnHud", true)
1656 entry.showOnInfoHud = xmlFile:getValue(key .. "#showOnInfoHud", true)
1657 entry.uiPrecision = xmlFile:getValue(key .. "#uiPrecision", 0)
1658 local unitText = xmlFile:getValue(key .. "#unitTextOverride")
1659 if unitText ~= nil then
1660 entry.unitText = g_i18n:convertText(unitText)
1661 end
1662 entry.parentUnitOnHud = nil
1663 entry.childUnitOnHud = nil
1664 entry.blocksAutomatedTrainTravel = xmlFile:getValue(key .. "#blocksAutomatedTrainTravel", false)
1665
1666 entry.fillAnimation = xmlFile:getValue(key .. "#fillAnimation")
1667 entry.fillAnimationLoadTime = xmlFile:getValue(key .. "#fillAnimationLoadTime")
1668 entry.fillAnimationEmptyTime = xmlFile:getValue(key .. "#fillAnimationEmptyTime")
1669
1670 entry.fillLevelAnimationName = xmlFile:getValue(key .. ".fillLevelAnimation#name")
1671 entry.fillLevelAnimationResetOnEmpty = xmlFile:getValue(key .. ".fillLevelAnimation#resetOnEmpty", true)
1672
1673
1674 --
1675 if self.isClient then
1676 entry.alarmTriggers = {}
1677 local i = 0
1678 while true do
1679 local nodeKey = key .. string.format(".alarmTriggers.alarmTrigger(%d)", i)
1680 if not xmlFile:hasProperty(nodeKey) then
1681 break
1682 end
1683 local alarmTrigger = {}
1684 if self:loadAlarmTrigger(xmlFile, nodeKey, alarmTrigger, entry) then
1685 table.insert(entry.alarmTriggers, alarmTrigger)
1686 end
1687 i = i + 1
1688 end
1689
1690 entry.measurementNodes = {}
1691 i = 0
1692 while true do
1693 local nodeKey = key .. string.format(".measurementNodes.measurementNode(%d)", i)
1694 if not xmlFile:hasProperty(nodeKey) then
1695 break
1696 end
1697
1698 local measurementNode = {}
1699 if self:loadMeasurementNode(xmlFile, nodeKey, measurementNode) then
1700 table.insert(entry.measurementNodes, measurementNode)
1701 end
1702
1703 i = i + 1
1704 end
1705
1706 entry.fillPlane = {}
1707 entry.lastFillPlaneType = nil
1708 if not self:loadFillPlane(xmlFile, key..".fillPlane", entry.fillPlane, entry) then
1709 entry.fillPlane = nil
1710 end
1711
1712 entry.fillTypeMaterials = self:loadFillTypeMaterials(xmlFile, key)
1713
1714 entry.fillEffects = g_effectManager:loadEffect(xmlFile, key .. ".fillEffect", self.components, self, self.i3dMappings)
1715 entry.animationNodes = g_animationManager:loadAnimations(xmlFile, key..".animationNodes", self.components, self, self.i3dMappings)
1716
1717 XMLUtil.checkDeprecatedXMLElements(xmlFile, key .. ".fillLevelHud", key .. ".dashboard") --FS17 to FS19
1718
1719 if self.loadDashboardsFromXML ~= nil then
1720 self:loadDashboardsFromXML(xmlFile, key, {valueTypeToLoad = "fillLevel",
1721 valueObject = entry,
1722 valueFunc = "fillLevel",
1723 minFunc = 0,
1724 maxFunc = "capacity"})
1725
1726 self:loadDashboardsFromXML(xmlFile, key, {valueTypeToLoad = "fillLevelPct",
1727 valueObject = entry,
1728 valueFunc = function(fillUnit)
1729 return MathUtil.clamp(fillUnit.fillLevel/fillUnit.capacity, 0, 1) * 100
1730 end,
1731 minFunc = 0,
1732 maxFunc = 100})
1733
1734 self:loadDashboardsFromXML(xmlFile, key, {valueTypeToLoad = "fillLevelWarning",
1735 valueObject = entry,
1736 valueFunc = "fillLevel",
1737 minFunc = 0,
1738 maxFunc = "capacity",
1739 additionalAttributesFunc = Dashboard.warningAttributes,
1740 stateFunc = Dashboard.warningState})
1741 end
1742 end
1743
1744 return true
1745end

loadFillUnitUnloadingFromXML

Description
Definition
loadFillUnitUnloadingFromXML()
Code
1155function FillUnit:loadFillUnitUnloadingFromXML(xmlFile, key, entry, index)
1156 entry.node = xmlFile:getValue(key.."#node", self.rootNode, self.components, self.i3dMappings)
1157 entry.width = xmlFile:getValue(key.."#width", 15)
1158 entry.offset = xmlFile:getValue(key.."#offset", "0 0 0", true)
1159
1160 return true
1161end

loadLevelerNodeFromXML

Description
Definition
loadLevelerNodeFromXML()
Code
2395function FillUnit:loadLevelerNodeFromXML(superFunc, levelerNode, xmlFile, key)
2396 levelerNode.limitFillUnitIndex = xmlFile:getValue(key.."#fillUnitIndex", 1)
2397 levelerNode.minFillLevel = xmlFile:getValue(key.."#minFillLevel", 0)
2398 levelerNode.maxFillLevel = xmlFile:getValue(key.."#maxFillLevel", 1)
2399
2400 return superFunc(self, levelerNode, xmlFile, key)
2401end

loadMeasurementNode

Description
Definition
loadMeasurementNode()
Code
1773function FillUnit:loadMeasurementNode(xmlFile, key, entry)
1774 XMLUtil.checkDeprecatedXMLElements(xmlFile, key.."#index", key.."#node")
1775
1776 local node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
1777 if node == nil then
1778 Logging.xmlWarning(self.xmlFile, "Missing 'node' for measurementNode '%s'", key)
1779 return false
1780 end
1781 entry.node = node
1782 entry.measurementTime = 0
1783 entry.intensity = 0
1784
1785 return true
1786end

loadMovingToolFromXML

Description
Definition
loadMovingToolFromXML()
Code
2294function FillUnit:loadMovingToolFromXML(superFunc, xmlFile, key, entry)
2295 if not superFunc(self, xmlFile, key, entry) then
2296 return false
2297 end
2298
2299 entry.fillUnitIndex = xmlFile:getValue(key .. "#fillUnitIndex")
2300 entry.minFillLevel = xmlFile:getValue(key .. "#minFillLevel")
2301 entry.maxFillLevel = xmlFile:getValue(key .. "#maxFillLevel")
2302
2303 return true
2304end

loadSpecValueCapacity

Description
Definition
loadSpecValueCapacity()
Code
2455function FillUnit.loadSpecValueCapacity(xmlFile, customEnvironment, baseDir)
2456 -- check if #unitText or #unit was set and convert capacity, liters otherwise
2457 local function getUnitCapacityAndText(fillUnitKey, capacity)
2458 local unitText = xmlFile:getValue(fillUnitKey .. "#unitTextOverride")
2459 if unitText == nil then
2460 local unitId = xmlFile:getValue(fillUnitKey .. "#shopDisplayUnit")
2461 local convFuncAndL10n = FillUnit.UNIT[unitId]
2462 if unitId ~= nil and convFuncAndL10n == nil then
2463 Logging.xmlWarning(xmlFile, "Unit '%s' is not defined in fillUnit '%s'. Available units: %s. Using LITER as default", unitId, fillUnitKey, table.concatKeys(FillUnit.UNIT, " "))
2464 end
2465 convFuncAndL10n = convFuncAndL10n or FillUnit.UNIT["LITER"]
2466 return convFuncAndL10n.conversionFunc(capacity), convFuncAndL10n.l10n, convFuncAndL10n.conversionFunc
2467 end
2468 return capacity, unitText
2469 end
2470
2471 local rootName = xmlFile:getRootName()
2472 local fillUnitConfigurations = {}
2473
2474 XMLUtil.checkDeprecatedXMLElements(xmlFile, rootName..".storeData.specs.capacity#unit", rootName..".storeData.specs.capacity#unitTextOverride") --FS19 to FS22
2475
2476 local overwrittenCapacity = xmlFile:getValue(rootName..".storeData.specs.capacity")
2477 local overwrittenUnitText
2478 local conversionFunc
2479
2480 if overwrittenCapacity ~= nil then
2481 overwrittenCapacity, overwrittenUnitText, conversionFunc = getUnitCapacityAndText(rootName..".storeData.specs.capacity", overwrittenCapacity)
2482 end
2483
2484 if overwrittenCapacity ~= nil and overwrittenUnitText ~= nil then
2485 table.insert(fillUnitConfigurations, {{capacity=overwrittenCapacity, unit=overwrittenUnitText, conversionFunc=conversionFunc}})
2486 return fillUnitConfigurations
2487 end
2488
2489 xmlFile:iterate(rootName..".fillUnit.fillUnitConfigurations.fillUnitConfiguration",function(_, key)
2490 local fillUnitConfiguration = {}
2491
2492 xmlFile:iterate(key..".fillUnits.fillUnit", function(fillUnitIndex, fillUnitKey)
2493
2494 XMLUtil.checkDeprecatedXMLElements(xmlFile, fillUnitKey.."#unit", fillUnitKey.."#unitTextOverride") --FS19 to FS22
2495
2496 if xmlFile:getValue(fillUnitKey.."#showCapacityInShop") ~= false and xmlFile:getValue(fillUnitKey.."#showInShop") ~= false then
2497 local capacity = xmlFile:getValue(fillUnitKey .. "#capacity") or 0
2498 local unitText
2499
2500 capacity, unitText, conversionFunc = getUnitCapacityAndText(fillUnitKey, capacity)
2501
2502 table.insert(fillUnitConfiguration, {capacity=capacity, unit=unitText, conversionFunc=conversionFunc, fillUnitIndex=fillUnitIndex})
2503 end
2504 end)
2505
2506 table.insert(fillUnitConfigurations, fillUnitConfiguration)
2507 end)
2508
2509 if #fillUnitConfigurations > 0 then
2510 return fillUnitConfigurations
2511 end
2512end

loadSpecValueFillTypes

Description
Definition
loadSpecValueFillTypes()
Code
2620function FillUnit.loadSpecValueFillTypes(xmlFile, customEnvironment, baseDir)
2621 local fillTypeNames = nil
2622 local fillTypeCategoryNames = nil
2623 local fillTypes = nil
2624 local fruitTypeNames = nil
2625 local fillTypesByConfiguration = {}
2626
2627 local rootName = xmlFile:getRootName()
2628
2629 XMLUtil.checkDeprecatedXMLElements(xmlFile, rootName..".fillTypes", rootName..".cutter#fruitTypes") --FS19 to FS21
2630 XMLUtil.checkDeprecatedXMLElements(xmlFile, rootName..".fruitTypes", rootName..".storeData.specs.fillTypes") --FS19 to FS21
2631 XMLUtil.checkDeprecatedXMLElements(xmlFile, rootName..".fillTypeCategories", rootName..".storeData.specs.fillTypeCategories") --FS19 to FS21
2632
2633 -- get fill types of all configurations and all fill units to display all possible fill types
2634 local i = 0
2635 while true do
2636 local key = string.format(rootName..".fillUnit.fillUnitConfigurations.fillUnitConfiguration(%d)", i)
2637 if not xmlFile:hasProperty(key) then
2638 break
2639 end
2640
2641 local j = 0
2642 while true do
2643 local unitKey = string.format(key..".fillUnits.fillUnit(%d)", j)
2644 if not xmlFile:hasProperty(unitKey) then
2645 break
2646 end
2647
2648 local showInShop = xmlFile:getValue(unitKey.."#showInShop")
2649 local capacity = xmlFile:getValue(unitKey.."#capacity")
2650 if (showInShop == nil or showInShop) and (capacity == nil or capacity > 0) then
2651 local currentFillTypes = xmlFile:getValue(unitKey .. "#fillTypes")
2652 if currentFillTypes ~= nil then
2653 if fillTypeNames == nil then
2654 fillTypeNames = currentFillTypes
2655 else
2656 fillTypeNames = fillTypeNames .. " " .. currentFillTypes
2657 end
2658 end
2659
2660 local currentFillTypeCategories = xmlFile:getValue(unitKey .. "#fillTypeCategories")
2661 if currentFillTypeCategories ~= nil then
2662 if fillTypeCategoryNames == nil then
2663 fillTypeCategoryNames = currentFillTypeCategories
2664 else
2665 fillTypeCategoryNames = fillTypeCategoryNames .. " " .. currentFillTypeCategories
2666 end
2667 end
2668
2669 fillTypesByConfiguration[i + 1] = {fillTypeNames=currentFillTypes, categoryNames=currentFillTypeCategories}
2670 end
2671
2672 j = j + 1
2673 end
2674
2675 i = i + 1
2676 end
2677
2678 local overwrittenFillTypeNames = xmlFile:getValue(rootName..".storeData.specs.fillTypes")
2679 if overwrittenFillTypeNames ~= nil then
2680 fillTypeNames = overwrittenFillTypeNames
2681 fillTypeCategoryNames = nil
2682 end
2683
2684 if fillTypes == nil then
2685 fruitTypeNames = xmlFile:getValue(rootName..".cutter#fruitTypes")
2686 end
2687
2688 local fruitTypeCategoryNames = xmlFile:getValue(rootName..".cutter#fruitTypeCategories")
2689 local useWindrowed = xmlFile:getValue(rootName..".cutter#useWindrowed", false)
2690
2691 fillTypeCategoryNames = xmlFile:getValue(rootName..".storeData.specs.fillTypeCategories", fillTypeCategoryNames)
2692
2693 return {categoryNames=fillTypeCategoryNames, fillTypeNames=fillTypeNames, fruitTypeNames=fruitTypeNames, fruitTypeCategoryNames=fruitTypeCategoryNames, useWindrowed=useWindrowed, fillTypesByConfiguration=fillTypesByConfiguration}
2694end

loadSpecValueFillUnitMassData

Description
Definition
loadSpecValueFillUnitMassData()
Code
2784function FillUnit.loadSpecValueFillUnitMassData(xmlFile, customEnvironment, baseDir)
2785 local fillUnitMassData = {}
2786 xmlFile:iterate("vehicle.motorized.consumerConfigurations.consumerConfiguration(0).consumer", function(index, key)
2787 local fillUnitIndex = xmlFile:getValue(key .. "#fillUnitIndex", 0)
2788 if fillUnitIndex ~= 0 then
2789 local unitKey = string.format("vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration(0).fillUnits.fillUnit(%d)", fillUnitIndex - 1)
2790
2791 local fillTypeCategories = xmlFile:getValue(unitKey .. "#fillTypeCategories")
2792 local fillTypes = xmlFile:getValue(unitKey .. "#fillTypes")
2793 local capacity = xmlFile:getValue(unitKey .. "#capacity", 0)
2794 if capacity > 0 then
2795 table.insert(fillUnitMassData, {fillTypeCategories=fillTypeCategories, fillTypes=fillTypes, capacity=capacity})
2796 end
2797 end
2798 end)
2799
2800 xmlFile:iterate("vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration(0).fillUnits.fillUnit", function(index, key)
2801 local startFillLevel = xmlFile:getValue(key .. "#startFillLevel", 0)
2802 if startFillLevel > 0 then
2803 local startFillType = xmlFile:getValue(key .. "#startFillType")
2804 table.insert(fillUnitMassData, {fillType=startFillType, capacity=startFillLevel})
2805 end
2806 end)
2807
2808 return fillUnitMassData
2809end

onDeactivate

Description
Definition
onDeactivate()
Code
712function FillUnit:onDeactivate()
713 local spec = self.spec_fillUnit
714 if spec.fillTrigger.isFilling then
715 self:setFillUnitIsFilling(false, true)
716 end
717
718 for _, fillUnit in pairs(spec.fillUnits) do
719 self:updateMeasurementNodes(fillUnit, 0, false, 0)
720 end
721end

onDelete

Description
Definition
onDelete()
Code
443function FillUnit:onDelete()
444 local spec = self.spec_fillUnit
445
446 if spec.fillTrigger ~= nil then
447 g_currentMission.activatableObjectsSystem:removeActivatable(spec.fillTrigger.activatable)
448 for _, trigger in pairs(spec.fillTrigger.triggers) do
449 trigger:onVehicleDeleted(self)
450 end
451 end
452
453 if spec.fillUnits ~= nil then
454 for _, fillUnit in ipairs(spec.fillUnits) do
455 for _, alarmTrigger in ipairs(fillUnit.alarmTriggers) do
456 g_soundManager:deleteSample(alarmTrigger.sample)
457 end
458 end
459 end
460
461 g_soundManager:deleteSamples(spec.samples)
462
463 if spec.unloadTrigger ~= nil then
464 spec.unloadTrigger:delete()
465 end
466 if spec.loadTrigger ~= nil then
467 spec.loadTrigger:delete()
468 end
469end

onDischargeTargetObjectChanged

Description
Definition
onDischargeTargetObjectChanged()
Code
754function FillUnit:onDischargeTargetObjectChanged(dischargeObject)
755 -- update unloading action event in case we overlap with the overloading action
756 FillUnit.updateUnloadActionDisplay(self)
757end

onDraw

Description
Definition
onDraw()
Code
703function FillUnit:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
704 if self:getDrawFirstFillText() then
705 local spec = self.spec_fillUnit
706 g_currentMission:addExtraPrintText(spec.texts.firstFillTheTool)
707 end
708end

onLoad

Description
Definition
onLoad()
Code
280function FillUnit:onLoad(savegame)
281 local spec = self.spec_fillUnit
282
283 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.measurementNodes.measurementNode", "vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration.fillUnits.fillUnit.measurementNodes.measurementNode")
284 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.fillPlanes.fillPlane", "vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration.fillUnits.fillUnit.fillPlane")
285 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.foldable.foldingParts#onlyFoldOnEmpty", "vehicle.fillUnit#allowFoldingWhileFilled")
286 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.fillAutoAimTargetNode", "vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration.fillUnits.fillUnit.autoAimTargetNode") --FS17 to FS19
287
288 local fillUnitConfigurationId = Utils.getNoNil(self.configurations["fillUnit"], 1)
289 local baseKey = string.format("vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration(%d).fillUnits", fillUnitConfigurationId -1)
290 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration", fillUnitConfigurationId , self.components, self)
291
292 spec.removeVehicleIfEmpty = self.xmlFile:getValue(baseKey.."#removeVehicleIfEmpty", false)
293 spec.removeVehicleDelay = self.xmlFile:getValue(baseKey.."#removeVehicleDelay", 0)
294 spec.allowFoldingWhileFilled = self.xmlFile:getValue(baseKey.."#allowFoldingWhileFilled", true)
295 spec.allowFoldingThreshold = self.xmlFile:getValue(baseKey.."#allowFoldingThreshold", 0.0001)
296 spec.fillTypeChangeThreshold = self.xmlFile:getValue(baseKey.."#fillTypeChangeThreshold", 0.05) -- fill level percentage that still allows overriding with another fill type
297 spec.fillUnits = {}
298 spec.exactFillRootNodeToFillUnit = {}
299 spec.exactFillRootNodeToExtraDistance = {}
300 spec.hasExactFillRootNodes = false
301 spec.activeAlarmTriggers = {}
302
303 spec.fillTrigger = {}
304 spec.fillTrigger.triggers = {}
305 spec.fillTrigger.activatable = FillActivatable.new(self)
306 spec.fillTrigger.isFilling = false
307 spec.fillTrigger.currentTrigger = nil -- trigger that is currently used for filling
308 spec.fillTrigger.selectedTrigger = nil -- currently used trigger no matter if filling or not
309 spec.fillTrigger.litersPerSecond = self.xmlFile:getValue(baseKey..".fillTrigger#litersPerSecond", 200)
310 spec.fillTrigger.consumePtoPower = self.xmlFile:getValue(baseKey..".fillTrigger#consumePtoPower", false)
311
312 local i=0
313 while true do
314 local key = string.format("%s.fillUnit(%d)", baseKey, i)
315 if not self.xmlFile:hasProperty(key) then
316 break
317 end
318 local entry = {}
319
320 if self:loadFillUnitFromXML(self.xmlFile, key, entry, i+1) then
321 table.insert(spec.fillUnits, entry)
322 else
323 Logging.xmlWarning(self.xmlFile, "Could not load fillUnit for '%s'", key)
324 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
325 break
326 end
327
328 i = i + 1
329 end
330
331 if self.xmlFile:hasProperty(baseKey..".unloading") then
332 spec.unloading = {}
333 self.xmlFile:iterate(baseKey ..".unloading", function(_, unloadingKey)
334 local entry = {}
335
336 if self:loadFillUnitUnloadingFromXML(self.xmlFile, unloadingKey, entry, i+1) then
337 table.insert(spec.unloading, entry)
338 else
339 Logging.xmlWarning(self.xmlFile, "Could not load unloading node for '%s'", unloadingKey)
340 return false
341 end
342 end)
343 end
344
345 if self.isClient then
346 spec.samples = {}
347 spec.samples.fill = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.fillUnit.sounds", "fill", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
348
349 spec.fillEffects = g_effectManager:loadEffect(self.xmlFile, baseKey .. ".fillEffect", self.components, self, self.i3dMappings)
350 spec.animationNodes = g_animationManager:loadAnimations(self.xmlFile, baseKey..".animationNodes", self.components, self, self.i3dMappings)
351
352 spec.activeFillEffects = {}
353 spec.activeFillAnimations = {}
354 end
355
356 spec.texts = {}
357 spec.texts.warningFoldingFilled = g_i18n:getText("warning_foldingNotWhileFilled")
358 spec.texts.firstFillTheTool = g_i18n:getText("info_firstFillTheTool")
359 spec.texts.unloadNoSpace = g_i18n:getText("fillUnit_unload_nospace")
360 spec.texts.stopRefill = g_i18n:getText("action_stopRefillingOBJECT")
361 spec.texts.startRefill = g_i18n:getText("action_refillOBJECT")
362
363 spec.isInfoDirty = false
364 spec.fillUnitInfos = {}
365
366 spec.dirtyFlag = self:getNextDirtyFlag()
367end

onPostLoad

Description
Definition
onPostLoad()
Code
371function FillUnit:onPostLoad(savegame)
372 local spec = self.spec_fillUnit
373
374 if self.isServer then
375 -- fill units that do not have a start fill level will be only loaded from savegame if not reseted and savegame available
376 local fillUnitsToLoad = {}
377 for i, fillUnit in ipairs(spec.fillUnits) do
378 if fillUnit.startFillLevel == nil and fillUnit.startFillTypeIndex == nil then
379 fillUnitsToLoad[i] = fillUnit
380 end
381 end
382
383 -- if the fill units are not in the savegame we fill them also with the start fill level (e.g. on a new savegame)
384 if savegame ~= nil and savegame.xmlFile:hasProperty(savegame.key..".fillUnit") then
385 local i = 0
386 local xmlFile = savegame.xmlFile
387 while true do
388 local key = string.format("%s.fillUnit.unit(%d)", savegame.key, i)
389 if not xmlFile:hasProperty(key) then
390 break
391 end
392
393 local fillUnitIndex = xmlFile:getValue(key.."#index")
394
395 local allowLoading = fillUnitsToLoad[fillUnitIndex] == nil or -- always load (fill unit with start fill level)
396 (fillUnitsToLoad[fillUnitIndex] ~= nil and not savegame.resetVehicles) -- only load if not reseted (fill unit without start fill level)
397 if allowLoading then
398 local fillTypeName = xmlFile:getValue(key.."#fillType")
399 local fillLevel = xmlFile:getValue(key.."#fillLevel")
400 local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeName)
401 self:addFillUnitFillLevel(self:getOwnerFarmId(), fillUnitIndex, fillLevel, fillTypeIndex, ToolType.UNDEFINED, nil)
402
403 local fillUnit = spec.fillUnits[fillUnitIndex]
404 if fillUnit ~= nil and fillUnit.fillLevelAnimationName ~= nil then
405 AnimatedVehicle.updateAnimationByName(self, fillUnit.fillLevelAnimationName, 9999999, true)
406 end
407 end
408
409 i = i + 1
410 end
411 else
412 -- fill units that are filled by a start fill level are always loaded from the savegame (otherwise you could cheat if you reset the vehicle)
413 for fillUnitIndex, fillUnit in pairs(spec.fillUnits) do
414 if fillUnit.startFillLevel ~= nil and fillUnit.startFillTypeIndex ~= nil then
415 self:addFillUnitFillLevel(self:getOwnerFarmId(), fillUnitIndex, fillUnit.startFillLevel, fillUnit.startFillTypeIndex, ToolType.UNDEFINED, nil)
416
417 if fillUnit.fillLevelAnimationName ~= nil then
418 AnimatedVehicle.updateAnimationByName(self, fillUnit.fillLevelAnimationName, 9999999, true)
419 end
420 end
421 end
422 end
423
424 for i, fillUnit in ipairs(spec.fillUnits) do
425 self:updateAlarmTriggers(fillUnit.alarmTriggers)
426 end
427 end
428
429 if #spec.fillUnits == 0 then
430 SpecializationUtil.removeEventListener(self, "onReadStream", FillUnit)
431 SpecializationUtil.removeEventListener(self, "onWriteStream", FillUnit)
432 SpecializationUtil.removeEventListener(self, "onReadUpdateStream", FillUnit)
433 SpecializationUtil.removeEventListener(self, "onWriteUpdateStream", FillUnit)
434 SpecializationUtil.removeEventListener(self, "onUpdateTick", FillUnit)
435 SpecializationUtil.removeEventListener(self, "onDraw", FillUnit)
436 SpecializationUtil.removeEventListener(self, "onDeactivate", FillUnit)
437 SpecializationUtil.removeEventListener(self, "onRegisterActionEvents", FillUnit)
438 end
439end

onReadStream

Description
Definition
onReadStream()
Code
512function FillUnit:onReadStream(streamId, connection)
513 if connection:getIsServer() then
514 local spec = self.spec_fillUnit
515
516 self:setFillUnitIsFilling(streamReadBool(streamId), true)
517
518 if spec.loadTrigger ~= nil then
519 local loadTriggerId = streamReadInt32(streamId)
520 spec.loadTrigger:readStream(streamId, connection)
521 g_client:finishRegisterObject(self.loadTrigger, loadTriggerId)
522 end
523 if spec.unloadTrigger ~= nil then
524 local unloadTriggerId = streamReadInt32(streamId)
525 spec.unloadTrigger:readStream(streamId, connection)
526 g_client:finishRegisterObject(self.unloadTrigger, unloadTriggerId)
527 end
528 for i=1,table.getn(spec.fillUnits) do
529 if spec.fillUnits[i].synchronizeFillLevel then
530 local fillLevel = streamReadFloat32(streamId)
531 local fillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS)
532
533 self:addFillUnitFillLevel(self:getOwnerFarmId(), i, fillLevel, fillType, ToolType.UNDEFINED, nil)
534
535 local lastValidFillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS)
536 self:setFillUnitLastValidFillType(i, lastValidFillType, true)
537 end
538 end
539 end
540end

onReadUpdateStream

Description
Definition
onReadUpdateStream()
Code
573function FillUnit:onReadUpdateStream(streamId, timestamp, connection)
574 if connection:getIsServer() then
575 local spec = self.spec_fillUnit
576
577 if streamReadBool(streamId) then
578 for i=1,table.getn(spec.fillUnits) do
579 local fillUnit = spec.fillUnits[i]
580 if fillUnit.synchronizeFillLevel then
581 local fillLevel
582 if fillUnit.synchronizeFullFillLevel then
583 fillLevel = streamReadFloat32(streamId)
584 else
585 local maxValue = 2^fillUnit.synchronizationNumBits - 1
586 fillLevel = fillUnit.capacity * streamReadUIntN(streamId, fillUnit.synchronizationNumBits) / maxValue
587 end
588
589 local fillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS)
590 if fillLevel ~= fillUnit.fillLevel or fillType ~= fillUnit.fillType then
591 local oldFillType = self:getFillUnitFillType(i)
592
593 -- if fill type is unknown we empty the fillUnit
594 if fillType == FillType.UNKNOWN then
595 self:addFillUnitFillLevel(self:getOwnerFarmId(), i, -math.huge, oldFillType, ToolType.UNDEFINED, nil)
596 else
597 -- in case the fill type was switched dynamically
598 if oldFillType ~= FillType.UNKNOWN and fillType ~= oldFillType then
599 self:setFillUnitFillType(i, fillType)
600 end
601
602 self:addFillUnitFillLevel(self:getOwnerFarmId(), i, fillLevel-fillUnit.fillLevel, fillType, ToolType.UNDEFINED, nil)
603 end
604 end
605
606 local lastValidFillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS)
607 self:setFillUnitLastValidFillType(i, lastValidFillType, lastValidFillType ~= fillUnit.lastValidFillType)
608 end
609 end
610 end
611 end
612end

onRegisterActionEvents

Description
Definition
onRegisterActionEvents()
Code
725function FillUnit:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
726 if self.isClient then
727 local spec = self.spec_fillUnit
728 self:clearActionEventsTable(spec.actionEvents)
729 if isActiveForInputIgnoreSelection then
730 if self.isServer and GS_IS_CONSOLE_VERSION and g_isDevelopmentVersion then
731 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CONSOLE_DEBUG_FILLUNIT_NEXT, self, FillUnit.actionEventConsoleFillUnitNext, false, true, false, true, nil)
732 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
733 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_LOW)
734 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CONSOLE_DEBUG_FILLUNIT_INC, self, FillUnit.actionEventConsoleFillUnitInc, false, true, false, true, nil)
735 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
736 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_LOW)
737 _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.CONSOLE_DEBUG_FILLUNIT_DEC, self, FillUnit.actionEventConsoleFillUnitDec, false, true, false, true, nil)
738 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
739 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_LOW)
740 end
741
742 if spec.unloading ~= nil then
743 local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.UNLOAD, self, FillUnit.actionEventUnload, false, true, false, true, nil)
744 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL)
745 spec.unloadActionEventId = actionEventId
746 FillUnit.updateUnloadActionDisplay(self)
747 end
748 end
749 end
750end

onUpdateTick

Description
Definition
onUpdateTick()
Code
645function FillUnit:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
646 local spec = self.spec_fillUnit
647
648 if self.isServer and spec.fillTrigger.isFilling then
649 local delta = 0
650 local trigger = spec.fillTrigger.currentTrigger
651 if trigger ~= nil then
652 delta = spec.fillTrigger.litersPerSecond*dt*0.001
653 delta = trigger:fillVehicle(self, delta, dt)
654 end
655
656 if delta <= 0 then
657 self:setFillUnitIsFilling(false)
658 end
659 end
660
661 if self.isClient then
662 for _, fillUnit in pairs(spec.fillUnits) do
663 self:updateMeasurementNodes(fillUnit, dt, false)
664 end
665
666 self:updateAlarmTriggers(spec.activeAlarmTriggers)
667
668
669 local needsUpdate = false
670
671 -- stop effects
672 for effect, time in pairs(spec.activeFillEffects) do
673 time = time - dt
674 if time < 0 then
675 g_effectManager:stopEffects(effect)
676 spec.activeFillEffects[effect] = nil
677 else
678 needsUpdate = true
679 spec.activeFillEffects[effect] = time
680 end
681 end
682
683 -- stop animations
684 for animationNodes, time in pairs(spec.activeFillAnimations) do
685 time = time - dt
686 if time < 0 then
687 g_animationManager:stopAnimations(animationNodes)
688 spec.activeFillAnimations[animationNodes] = nil
689 else
690 needsUpdate = true
691 spec.activeFillAnimations[animationNodes] = time
692 end
693 end
694
695 if needsUpdate then
696 self:raiseActive()
697 end
698 end
699end

onWriteStream

Description
Definition
onWriteStream()
Code
544function FillUnit:onWriteStream(streamId, connection)
545 if not connection:getIsServer() then
546 local spec = self.spec_fillUnit
547
548 streamWriteBool(streamId, spec.fillTrigger.isFilling)
549
550 if spec.loadTrigger ~= nil then
551 streamWriteInt32(streamId, NetworkUtil.getObjectId(spec.loadTrigger))
552 spec.loadTrigger:writeStream(streamId, connection)
553 g_server:registerObjectInStream(connection, spec.loadTrigger)
554 end
555 if spec.unloadTrigger ~= nil then
556 streamWriteInt32(streamId, NetworkUtil.getObjectId(spec.unloadTrigger))
557 spec.unloadTrigger:writeStream(streamId, connection)
558 g_server:registerObjectInStream(connection, spec.unloadTrigger)
559 end
560 for i=1,table.getn(spec.fillUnits) do
561 if spec.fillUnits[i].synchronizeFillLevel then
562 local fillUnit = spec.fillUnits[i]
563 streamWriteFloat32(streamId, fillUnit.fillLevel)
564 streamWriteUIntN(streamId, fillUnit.fillType, FillTypeManager.SEND_NUM_BITS)
565 streamWriteUIntN(streamId, fillUnit.lastValidFillType, FillTypeManager.SEND_NUM_BITS)
566 end
567 end
568 end
569end

onWriteUpdateStream

Description
Definition
onWriteUpdateStream()
Code
616function FillUnit:onWriteUpdateStream(streamId, connection, dirtyMask)
617 if not connection:getIsServer() then
618 local spec = self.spec_fillUnit
619
620 if streamWriteBool(streamId, bitAND(dirtyMask, spec.dirtyFlag) ~= 0) then
621 for i=1,table.getn(spec.fillUnits) do
622 local fillUnit = spec.fillUnits[i]
623 if fillUnit.synchronizeFillLevel then
624 if fillUnit.synchronizeFullFillLevel then
625 streamWriteFloat32(streamId, fillUnit.fillLevelSent)
626 else
627 local percent = 0
628 if fillUnit.capacity > 0 then
629 percent = MathUtil.clamp(fillUnit.fillLevelSent / fillUnit.capacity, 0, 1)
630 end
631
632 local value = math.floor(percent * (2^fillUnit.synchronizationNumBits - 1) + 0.5)
633 streamWriteUIntN(streamId, value, fillUnit.synchronizationNumBits)
634 end
635 streamWriteUIntN(streamId, fillUnit.fillTypeSent, FillTypeManager.SEND_NUM_BITS)
636 streamWriteUIntN(streamId, fillUnit.lastValidFillTypeSent, FillTypeManager.SEND_NUM_BITS)
637 end
638 end
639 end
640 end
641end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
162function FillUnit.prerequisitesPresent(specializations)
163 return true
164end

registerEventListeners

Description
Definition
registerEventListeners()
Code
263function FillUnit.registerEventListeners(vehicleType)
264 SpecializationUtil.registerEventListener(vehicleType, "onLoad", FillUnit)
265 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", FillUnit)
266 SpecializationUtil.registerEventListener(vehicleType, "onDelete", FillUnit)
267 SpecializationUtil.registerEventListener(vehicleType, "onReadStream", FillUnit)
268 SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", FillUnit)
269 SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", FillUnit)
270 SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", FillUnit)
271 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", FillUnit)
272 SpecializationUtil.registerEventListener(vehicleType, "onDraw", FillUnit)
273 SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", FillUnit)
274 SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", FillUnit)
275 SpecializationUtil.registerEventListener(vehicleType, "onDischargeTargetObjectChanged", FillUnit)
276end

registerEvents

Description
Definition
registerEvents()
Code
168function FillUnit.registerEvents(vehicleType)
169 SpecializationUtil.registerEvent(vehicleType, "onFillUnitFillLevelChanged")
170 SpecializationUtil.registerEvent(vehicleType, "onChangedFillType")
171 SpecializationUtil.registerEvent(vehicleType, "onAlarmTriggerChanged")
172 SpecializationUtil.registerEvent(vehicleType, "onAddedFillUnitTrigger")
173 SpecializationUtil.registerEvent(vehicleType, "onFillUnitTriggerChanged")
174 SpecializationUtil.registerEvent(vehicleType, "onRemovedFillUnitTrigger")
175 SpecializationUtil.registerEvent(vehicleType, "onFillUnitIsFillingStateChanged")
176end

registerFunctions

Description
Definition
registerFunctions()
Code
180function FillUnit.registerFunctions(vehicleType)
181 SpecializationUtil.registerFunction(vehicleType, "getDrawFirstFillText", FillUnit.getDrawFirstFillText)
182 SpecializationUtil.registerFunction(vehicleType, "getFillUnits", FillUnit.getFillUnits)
183 SpecializationUtil.registerFunction(vehicleType, "getFillUnitByIndex", FillUnit.getFillUnitByIndex)
184 SpecializationUtil.registerFunction(vehicleType, "getFillUnitExists", FillUnit.getFillUnitExists)
185 SpecializationUtil.registerFunction(vehicleType, "getFillUnitCapacity", FillUnit.getFillUnitCapacity)
186 SpecializationUtil.registerFunction(vehicleType, "getFillUnitFreeCapacity", FillUnit.getFillUnitFreeCapacity)
187 SpecializationUtil.registerFunction(vehicleType, "getIsFillAllowedFromFarm", FillUnit.getIsFillAllowedFromFarm)
188 SpecializationUtil.registerFunction(vehicleType, "getFillUnitFillLevel", FillUnit.getFillUnitFillLevel)
189 SpecializationUtil.registerFunction(vehicleType, "getFillUnitFillLevelPercentage", FillUnit.getFillUnitFillLevelPercentage)
190 SpecializationUtil.registerFunction(vehicleType, "getFillUnitFillType", FillUnit.getFillUnitFillType)
191 SpecializationUtil.registerFunction(vehicleType, "getFillUnitLastValidFillType", FillUnit.getFillUnitLastValidFillType)
192 SpecializationUtil.registerFunction(vehicleType, "getFillUnitFirstSupportedFillType", FillUnit.getFillUnitFirstSupportedFillType)
193 SpecializationUtil.registerFunction(vehicleType, "getFillUnitExactFillRootNode", FillUnit.getFillUnitExactFillRootNode)
194 SpecializationUtil.registerFunction(vehicleType, "getFillUnitRootNode", FillUnit.getFillUnitRootNode)
195 SpecializationUtil.registerFunction(vehicleType, "getFillUnitAutoAimTargetNode", FillUnit.getFillUnitAutoAimTargetNode)
196 SpecializationUtil.registerFunction(vehicleType, "getFillUnitSupportsFillType", FillUnit.getFillUnitSupportsFillType)
197 SpecializationUtil.registerFunction(vehicleType, "getFillUnitSupportsToolType", FillUnit.getFillUnitSupportsToolType)
198 SpecializationUtil.registerFunction(vehicleType, "getFillUnitSupportsToolTypeAndFillType", FillUnit.getFillUnitSupportsToolTypeAndFillType)
199 SpecializationUtil.registerFunction(vehicleType, "getFillUnitSupportedFillTypes", FillUnit.getFillUnitSupportedFillTypes)
200 SpecializationUtil.registerFunction(vehicleType, "getFillUnitSupportedToolTypes", FillUnit.getFillUnitSupportedToolTypes)
201 SpecializationUtil.registerFunction(vehicleType, "getFillUnitAllowsFillType", FillUnit.getFillUnitAllowsFillType)
202 SpecializationUtil.registerFunction(vehicleType, "getFillTypeChangeThreshold", FillUnit.getFillTypeChangeThreshold)
203 SpecializationUtil.registerFunction(vehicleType, "getFirstValidFillUnitToFill", FillUnit.getFirstValidFillUnitToFill)
204 SpecializationUtil.registerFunction(vehicleType, "setFillUnitFillType", FillUnit.setFillUnitFillType)
205 SpecializationUtil.registerFunction(vehicleType, "setFillUnitFillTypeToDisplay", FillUnit.setFillUnitFillTypeToDisplay)
206 SpecializationUtil.registerFunction(vehicleType, "setFillUnitFillLevelToDisplay", FillUnit.setFillUnitFillLevelToDisplay)
207 SpecializationUtil.registerFunction(vehicleType, "setFillUnitCapacity", FillUnit.setFillUnitCapacity)
208 SpecializationUtil.registerFunction(vehicleType, "setFillUnitForcedMaterialFillType", FillUnit.setFillUnitForcedMaterialFillType)
209 SpecializationUtil.registerFunction(vehicleType, "getFillUnitForcedMaterialFillType", FillUnit.getFillUnitForcedMaterialFillType)
210 SpecializationUtil.registerFunction(vehicleType, "updateAlarmTriggers", FillUnit.updateAlarmTriggers)
211 SpecializationUtil.registerFunction(vehicleType, "getAlarmTriggerIsActive", FillUnit.getAlarmTriggerIsActive)
212 SpecializationUtil.registerFunction(vehicleType, "setAlarmTriggerState", FillUnit.setAlarmTriggerState)
213 SpecializationUtil.registerFunction(vehicleType, "getFillUnitIndexFromNode", FillUnit.getFillUnitIndexFromNode)
214 SpecializationUtil.registerFunction(vehicleType, "getFillUnitExtraDistanceFromNode", FillUnit.getFillUnitExtraDistanceFromNode)
215 SpecializationUtil.registerFunction(vehicleType, "getFillUnitFromNode", FillUnit.getFillUnitFromNode)
216 SpecializationUtil.registerFunction(vehicleType, "addFillUnitFillLevel", FillUnit.addFillUnitFillLevel)
217 SpecializationUtil.registerFunction(vehicleType, "setFillUnitLastValidFillType", FillUnit.setFillUnitLastValidFillType)
218 SpecializationUtil.registerFunction(vehicleType, "loadFillUnitFromXML", FillUnit.loadFillUnitFromXML)
219 SpecializationUtil.registerFunction(vehicleType, "loadAlarmTrigger", FillUnit.loadAlarmTrigger)
220 SpecializationUtil.registerFunction(vehicleType, "loadMeasurementNode", FillUnit.loadMeasurementNode)
221 SpecializationUtil.registerFunction(vehicleType, "updateMeasurementNodes", FillUnit.updateMeasurementNodes)
222 SpecializationUtil.registerFunction(vehicleType, "loadFillPlane", FillUnit.loadFillPlane)
223 SpecializationUtil.registerFunction(vehicleType, "setFillPlaneForcedFillType", FillUnit.setFillPlaneForcedFillType)
224 SpecializationUtil.registerFunction(vehicleType, "updateFillUnitFillPlane", FillUnit.updateFillUnitFillPlane)
225 SpecializationUtil.registerFunction(vehicleType, "loadFillTypeMaterials", FillUnit.loadFillTypeMaterials)
226 SpecializationUtil.registerFunction(vehicleType, "updateFillTypeMaterials", FillUnit.updateFillTypeMaterials)
227 SpecializationUtil.registerFunction(vehicleType, "updateFillUnitAutoAimTarget", FillUnit.updateFillUnitAutoAimTarget)
228 SpecializationUtil.registerFunction(vehicleType, "addFillUnitTrigger", FillUnit.addFillUnitTrigger)
229 SpecializationUtil.registerFunction(vehicleType, "removeFillUnitTrigger", FillUnit.removeFillUnitTrigger)
230 SpecializationUtil.registerFunction(vehicleType, "setFillUnitIsFilling", FillUnit.setFillUnitIsFilling)
231 SpecializationUtil.registerFunction(vehicleType, "setFillSoundIsPlaying", FillUnit.setFillSoundIsPlaying)
232 SpecializationUtil.registerFunction(vehicleType, "getIsFillUnitActive", FillUnit.getIsFillUnitActive)
233 SpecializationUtil.registerFunction(vehicleType, "updateFillUnitTriggers", FillUnit.updateFillUnitTriggers)
234 SpecializationUtil.registerFunction(vehicleType, "emptyAllFillUnits", FillUnit.emptyAllFillUnits)
235 SpecializationUtil.registerFunction(vehicleType, "unloadFillUnits", FillUnit.unloadFillUnits)
236 SpecializationUtil.registerFunction(vehicleType, "loadFillUnitUnloadingFromXML", FillUnit.loadFillUnitUnloadingFromXML)
237 SpecializationUtil.registerFunction(vehicleType, "getAllowLoadTriggerActivation", FillUnit.getAllowLoadTriggerActivation)
238 SpecializationUtil.registerFunction(vehicleType, "debugGetSupportedFillTypesPerFillUnit", FillUnit.debugGetSupportedFillTypesPerFillUnit)
239end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
244function FillUnit.registerOverwrittenFunctions(vehicleType)
245 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAdditionalComponentMass", FillUnit.getAdditionalComponentMass)
246 SpecializationUtil.registerOverwrittenFunction(vehicleType, "addNodeObjectMapping", FillUnit.addNodeObjectMapping)
247 SpecializationUtil.registerOverwrittenFunction(vehicleType, "removeNodeObjectMapping", FillUnit.removeNodeObjectMapping)
248 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillLevelInformation", FillUnit.getFillLevelInformation)
249 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsFoldAllowed", FillUnit.getIsFoldAllowed)
250 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsReadyForAutomatedTrainTravel", FillUnit.getIsReadyForAutomatedTrainTravel)
251 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadMovingToolFromXML", FillUnit.loadMovingToolFromXML)
252 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsMovingToolActive", FillUnit.getIsMovingToolActive)
253 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDoConsumePtoPower", FillUnit.getDoConsumePtoPower)
254 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsPowerTakeOffActive", FillUnit.getIsPowerTakeOffActive)
255 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn", FillUnit.getCanBeTurnedOn)
256 SpecializationUtil.registerOverwrittenFunction(vehicleType, "showInfo", FillUnit.showInfo)
257 SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadLevelerNodeFromXML", FillUnit.loadLevelerNodeFromXML)
258 SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsLevelerPickupNodeActive", FillUnit.getIsLevelerPickupNodeActive)
259end

registerUnitDisplaySchema

Description
Definition
registerUnitDisplaySchema()
Code
155function FillUnit.registerUnitDisplaySchema(schema, key)
156 schema:register(XMLValueType.STRING, key .. "#shopDisplayUnit", "Unit used for displaying the capacity in shop (converts to given unit from capacity in liters)", "LITER")
157 schema:register(XMLValueType.STRING, key .. "#unitTextOverride", "Unit text override, no conversion performed on given capacity")
158end

removeFillUnitTrigger

Description
Removes fill trigger
Definition
removeFillUnitTrigger(table trigger)
Arguments
tabletriggertrigger
Code
2043function FillUnit:removeFillUnitTrigger(trigger)
2044 local spec = self.spec_fillUnit
2045 table.removeElement(spec.fillTrigger.triggers, trigger)
2046
2047 if self.isServer and trigger == spec.fillTrigger.currentTrigger then
2048 self:setFillUnitIsFilling(false)
2049 end
2050
2051 if #spec.fillTrigger.triggers == 0 then
2052 g_currentMission.activatableObjectsSystem:removeActivatable(spec.fillTrigger.activatable)
2053
2054 -- automatic filling for mobile version
2055 if self.isServer and Platform.gameplay.automaticFilling then
2056 self:setFillUnitIsFilling(false)
2057 end
2058 end
2059
2060 SpecializationUtil.raiseEvent(self, "onRemovedFillUnitTrigger", #spec.fillTrigger.triggers)
2061
2062 self:updateFillUnitTriggers()
2063end

removeNodeObjectMapping

Description
Definition
removeNodeObjectMapping()
Code
2199function FillUnit:removeNodeObjectMapping(superFunc, list)
2200 superFunc(self, list)
2201
2202 local spec = self.spec_fillUnit
2203
2204 if spec.fillUnits ~= nil then
2205 for _,fillUnit in pairs(spec.fillUnits) do
2206 if fillUnit.fillRootNode ~= nil then
2207 list[fillUnit.fillRootNode] = nil
2208 end
2209 if fillUnit.exactFillRootNode ~= nil then
2210 list[fillUnit.exactFillRootNode] = nil
2211 end
2212 end
2213 end
2214end

saveStatsToXMLFile

Description
Definition
saveStatsToXMLFile()
Code
490function FillUnit:saveStatsToXMLFile(xmlFile, key)
491 local spec = self.spec_fillUnit
492
493 local fillTypes = ''
494 local fillLevels = ''
495 local numFillUnits = table.getn(spec.fillUnits)
496 for i,fillUnit in ipairs(spec.fillUnits) do
497 local fillTypeName = Utils.getNoNil(g_fillTypeManager:getFillTypeNameByIndex(fillUnit.fillType), "unknown")
498 fillTypes = fillTypes .. HTMLUtil.encodeToHTML(tostring(fillTypeName))
499 fillLevels = fillLevels .. string.format("%.3f", fillUnit.fillLevel)
500 if numFillUnits > 1 and i ~= numFillUnits then
501 fillTypes = fillTypes .. ' '
502 fillLevels = fillLevels .. ' '
503 end
504 end
505
506 setXMLString(xmlFile, key.."#fillTypes", fillTypes)
507 setXMLString(xmlFile, key.."#fillLevels", fillLevels)
508end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
473function FillUnit:saveToXMLFile(xmlFile, key, usedModNames)
474 local spec = self.spec_fillUnit
475 local i = 0
476 for k, fillUnit in ipairs(spec.fillUnits) do
477 if fillUnit.needsSaving then
478 local fillUnitKey = string.format("%s.unit(%d)", key, i)
479 local fillTypeName = Utils.getNoNil(g_fillTypeManager:getFillTypeNameByIndex(fillUnit.fillType), "unknown")
480 xmlFile:setValue(fillUnitKey.."#index", k)
481 xmlFile:setValue(fillUnitKey.."#fillType", fillTypeName)
482 xmlFile:setValue(fillUnitKey.."#fillLevel", fillUnit.fillLevel)
483 i = i + 1
484 end
485 end
486end

setAlarmTriggerState

Description
Definition
setAlarmTriggerState()
Code
1089function FillUnit:setAlarmTriggerState(alarmTrigger, state)
1090 local spec = self.spec_fillUnit
1091
1092 if state ~= alarmTrigger.isActive then
1093 if state then
1094 if alarmTrigger.sample ~= nil then
1095 g_soundManager:playSample(alarmTrigger.sample)
1096 end
1097 spec.activeAlarmTriggers[alarmTrigger] = alarmTrigger
1098 else
1099 if alarmTrigger.sample ~= nil then
1100 g_soundManager:stopSample(alarmTrigger.sample)
1101 end
1102 spec.activeAlarmTriggers[alarmTrigger] = nil
1103 end
1104
1105 alarmTrigger.isActive = state
1106 SpecializationUtil.raiseEvent(self, "onAlarmTriggerChanged", alarmTrigger, state)
1107 end
1108end

setFillPlaneForcedFillType

Description
Definition
setFillPlaneForcedFillType()
Code
1909function FillUnit:setFillPlaneForcedFillType(fillUnitIndex, forcedFillType)
1910 local spec = self.spec_fillUnit
1911 if spec.fillUnits[fillUnitIndex] ~= nil then
1912 if spec.fillUnits[fillUnitIndex].fillPlane ~= nil then
1913 spec.fillUnits[fillUnitIndex].fillPlane.forcedFillType = forcedFillType
1914 end
1915 end
1916end

setFillSoundIsPlaying

Description
Definition
setFillSoundIsPlaying()
Code
2142function FillUnit:setFillSoundIsPlaying(isPlaying)
2143 local spec = self.spec_fillUnit
2144 if isPlaying then
2145 if not g_soundManager:getIsSamplePlaying(spec.samples.fill) then
2146 g_soundManager:playSample(spec.samples.fill)
2147 end
2148 else
2149 if g_soundManager:getIsSamplePlaying(spec.samples.fill) then
2150 g_soundManager:stopSample(spec.samples.fill)
2151 end
2152 end
2153end

setFillUnitCapacity

Description
Definition
setFillUnitCapacity()
Code
1029function FillUnit:setFillUnitCapacity(fillUnitIndex, capacity, noEventSend)
1030 local spec = self.spec_fillUnit
1031 if spec.fillUnits[fillUnitIndex] ~= nil then
1032 if capacity ~= spec.fillUnits[fillUnitIndex].capacity then
1033 spec.fillUnits[fillUnitIndex].capacity = capacity
1034
1035 SetFillUnitCapacityEvent.sendEvent(self, fillUnitIndex, capacity, noEventSend)
1036 end
1037 end
1038end

setFillUnitFillLevelToDisplay

Description
Definition
setFillUnitFillLevelToDisplay()
Code
1019function FillUnit:setFillUnitFillLevelToDisplay(fillUnitIndex, fillLevel, isPersistent)
1020 local spec = self.spec_fillUnit
1021 if spec.fillUnits[fillUnitIndex] ~= nil then
1022 spec.fillUnits[fillUnitIndex].fillLevelToDisplay = fillLevel
1023 spec.fillUnits[fillUnitIndex].fillLevelToDisplayIsPersistent = isPersistent ~= nil and isPersistent
1024 end
1025end

setFillUnitFillType

Description
Definition
setFillUnitFillType()
Code
998function FillUnit:setFillUnitFillType(fillUnitIndex, fillTypeIndex)
999 local spec = self.spec_fillUnit
1000 local oldFillTypeIndex = spec.fillUnits[fillUnitIndex].fillType
1001 if oldFillTypeIndex ~= fillTypeIndex then
1002 spec.fillUnits[fillUnitIndex].fillType = fillTypeIndex
1003 SpecializationUtil.raiseEvent(self, "onChangedFillType", fillUnitIndex, fillTypeIndex, oldFillTypeIndex)
1004 end
1005end

setFillUnitFillTypeToDisplay

Description
Definition
setFillUnitFillTypeToDisplay()
Code
1009function FillUnit:setFillUnitFillTypeToDisplay(fillUnitIndex, fillTypeIndex, isPersistent)
1010 local spec = self.spec_fillUnit
1011 if spec.fillUnits[fillUnitIndex] ~= nil then
1012 spec.fillUnits[fillUnitIndex].fillTypeToDisplay = fillTypeIndex
1013 spec.fillUnits[fillUnitIndex].fillTypeToDisplayIsPersistent = isPersistent ~= nil and isPersistent
1014 end
1015end

setFillUnitForcedMaterialFillType

Description
Definition
setFillUnitForcedMaterialFillType()
Code
1042function FillUnit:setFillUnitForcedMaterialFillType(fillUnitIndex, forcedMaterialFillType)
1043 local spec = self.spec_fillUnit
1044 if spec.fillUnits[fillUnitIndex] ~= nil then
1045 spec.fillUnits[fillUnitIndex].forcedMaterialFillType = forcedMaterialFillType
1046 end
1047
1048 self:setFillPlaneForcedFillType(fillUnitIndex, forcedMaterialFillType)
1049
1050 if self.setFillVolumeForcedFillTypeByFillUnitIndex ~= nil then
1051 self:setFillVolumeForcedFillTypeByFillUnitIndex(fillUnitIndex, forcedMaterialFillType)
1052 end
1053end

setFillUnitIsFilling

Description
Definition
setFillUnitIsFilling()
Code
2102function FillUnit:setFillUnitIsFilling(isFilling, noEventSend)
2103 local spec = self.spec_fillUnit
2104 if isFilling ~= spec.fillTrigger.isFilling then
2105 if noEventSend == nil or noEventSend == false then
2106 if g_server ~= nil then
2107 g_server:broadcastEvent(SetFillUnitIsFillingEvent.new(self, isFilling), nil, nil, self)
2108 else
2109 g_client:getServerConnection():sendEvent(SetFillUnitIsFillingEvent.new(self, isFilling))
2110 end
2111 end
2112
2113 spec.fillTrigger.isFilling = isFilling
2114 if isFilling then
2115 -- find the first trigger which is activable
2116 spec.fillTrigger.currentTrigger = nil
2117 for _, trigger in ipairs(spec.fillTrigger.triggers) do
2118 if trigger:getIsActivatable(self) then
2119 spec.fillTrigger.currentTrigger = trigger
2120 break
2121 end
2122 end
2123 end
2124 if self.isClient then
2125 self:setFillSoundIsPlaying(isFilling)
2126
2127 if spec.fillTrigger.currentTrigger ~= nil then
2128 spec.fillTrigger.currentTrigger:setFillSoundIsPlaying(isFilling)
2129 end
2130 end
2131
2132 SpecializationUtil.raiseEvent(self, "onFillUnitIsFillingStateChanged", isFilling)
2133
2134 if not isFilling then
2135 self:updateFillUnitTriggers()
2136 end
2137 end
2138end

setFillUnitLastValidFillType

Description
Definition
setFillUnitLastValidFillType()
Code
1524function FillUnit:setFillUnitLastValidFillType(fillUnitIndex, fillType, force)
1525 local spec = self.spec_fillUnit
1526 local fillUnit = spec.fillUnits[fillUnitIndex]
1527 if fillUnit ~= nil and fillUnit.lastValidFillType ~= fillType then
1528 fillUnit.lastValidFillType = fillType
1529 fillUnit.lastValidFillTypeSent = fillType
1530 self:raiseDirtyFlags(spec.dirtyFlag)
1531 end
1532end

showInfo

Description
Definition
showInfo()
Code
2349function FillUnit:showInfo(superFunc, box)
2350 local spec = self.spec_fillUnit
2351
2352 if spec.isInfoDirty then
2353 spec.fillUnitInfos = {}
2354 local fillTypeToInfo = {}
2355
2356 for _, fillUnit in ipairs(spec.fillUnits) do
2357 if fillUnit.showOnInfoHud and fillUnit.fillLevel > 0 then
2358 local info = fillTypeToInfo[fillUnit.fillType]
2359 if info == nil then
2360 local fillType = g_fillTypeManager:getFillTypeByIndex(fillUnit.fillType)
2361 info = {title=fillType.title, fillLevel=0, unit=fillUnit.unitText, precision=0}
2362 table.insert(spec.fillUnitInfos, info)
2363 fillTypeToInfo[fillUnit.fillType] = info
2364 end
2365
2366 info.fillLevel = info.fillLevel + fillUnit.fillLevel
2367 if info.precision == 0 and fillUnit.fillLevel > 0 then
2368 info.precision = fillUnit.uiPrecision or 0
2369 end
2370 end
2371 end
2372
2373 spec.isInfoDirty = false
2374 end
2375
2376 for _, info in ipairs(spec.fillUnitInfos) do
2377 local formattedNumber
2378 if info.precision > 0 then
2379 local rounded = MathUtil.round(info.fillLevel, info.precision)
2380 formattedNumber = string.format("%d%s%0"..info.precision.."d", math.floor(rounded), g_i18n.decimalSeparator, (rounded - math.floor(rounded)) * 10 ^ info.precision)
2381 else
2382 formattedNumber = string.format("%d", MathUtil.round(info.fillLevel))
2383 end
2384
2385 formattedNumber = formattedNumber .. " " .. (info.unit or g_i18n:getVolumeUnit())
2386
2387 box:addLine(info.title, formattedNumber)
2388 end
2389
2390 superFunc(self, box)
2391end

unloadFillUnits

Description
Definition
unloadFillUnits()
Code
1175function FillUnit:unloadFillUnits(ignoreWarning)
1176 if not self.isServer then
1177 g_client:getServerConnection():sendEvent(FillUnitUnloadEvent.new(self))
1178 else
1179 local spec = self.spec_fillUnit
1180 if spec.unloadingFillUnitsRunning then
1181 return
1182 end
1183
1184 local unloadingPlaces = spec.unloading
1185
1186 local places = {}
1187
1188 for _, unloading in ipairs(unloadingPlaces) do
1189 local node = unloading.node
1190 local ox, oy, oz = unpack(unloading.offset)
1191 local x, y, z = localToWorld(node, ox - unloading.width*0.5, oy, oz)
1192
1193 local place = {}
1194 place.startX, place.startY, place.startZ = x, y, z
1195 place.rotX, place.rotY, place.rotZ = getWorldRotation(node)
1196 place.dirX, place.dirY, place.dirZ = localDirectionToWorld(node, 1, 0, 0)
1197 place.dirPerpX, place.dirPerpY, place.dirPerpZ = localDirectionToWorld(node, 0, 0, 1)
1198 place.yOffset = 1
1199 place.maxWidth = math.huge
1200 place.maxLength = math.huge
1201 place.maxHeight = math.huge
1202 place.width = unloading.width
1203
1204 table.insert(places, place)
1205 end
1206
1207 local usedPlaces = {}
1208 local success = true
1209
1210 local availablePallets = {}
1211
1212 local unloadingTasks = {}
1213 for k, fillUnit in ipairs(self:getFillUnits()) do
1214 local fillLevel = self:getFillUnitFillLevel(k)
1215 local fillTypeIndex = self:getFillUnitFillType(k)
1216 local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex)
1217 if fillUnit.canBeUnloaded and fillLevel > 0 and fillType.palletFilename ~= nil then
1218 table.insert(unloadingTasks, {fillUnitIndex=k, fillTypeIndex=fillTypeIndex, fillLevel=fillLevel, filename=fillType.palletFilename})
1219 end
1220 end
1221
1222 local function unloadNext()
1223 local task = unloadingTasks[1]
1224 if task ~= nil then
1225 -- try to fill existing pallets
1226 for pallet, _ in pairs(availablePallets) do
1227 local fillUnitIndex = pallet:getFirstValidFillUnitToFill(task.fillTypeIndex)
1228 if fillUnitIndex ~= nil then
1229 local appliedDelta = pallet:addFillUnitFillLevel(self:getOwnerFarmId(), fillUnitIndex, task.fillLevel, task.fillTypeIndex, ToolType.UNDEFINED, nil)
1230 self:addFillUnitFillLevel(self:getOwnerFarmId(), task.fillUnitIndex, -appliedDelta, task.fillTypeIndex, ToolType.UNDEFINED, nil)
1231 task.fillLevel = task.fillLevel - appliedDelta
1232
1233 -- remove filled pallets
1234 if pallet:getFillUnitFreeCapacity(fillUnitIndex) <= 0 then
1235 availablePallets[pallet] = nil
1236 end
1237 end
1238 end
1239
1240 if task.fillLevel > 0 then
1241 local asyncCallback = function(_, vehicle, vehicleLoadState, arguments)
1242 if vehicleLoadState == VehicleLoadingUtil.VEHICLE_LOAD_OK then
1243 vehicle:emptyAllFillUnits(true)
1244 availablePallets[vehicle] = true
1245 unloadNext()
1246 end
1247 end
1248
1249
1250 local size = StoreItemUtil.getSizeValues(task.filename, "vehicle", 0, {})
1251 local x, y, z, place, width, _ = PlacementUtil.getPlace(places, size, usedPlaces, true, true, true)
1252
1253 if x == nil then
1254 success = false
1255
1256 if ignoreWarning == nil or not ignoreWarning then
1257 if not success then
1258 g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, spec.texts.unloadNoSpace)
1259 end
1260 end
1261
1262 return
1263 end
1264
1265 PlacementUtil.markPlaceUsed(usedPlaces, place, width)
1266 local location = {x=x, y=y, z=z, yRot=place.rotY}
1267
1268 VehicleLoadingUtil.loadVehicle(task.filename, location, true, 0, Vehicle.PROPERTY_STATE_OWNED, self:getOwnerFarmId(), nil, nil, asyncCallback, nil)
1269 else
1270 table.remove(unloadingTasks, 1)
1271 unloadNext()
1272 end
1273 end
1274 end
1275
1276 unloadNext()
1277 end
1278end

updateAlarmTriggers

Description
Definition
updateAlarmTriggers()
Code
1068function FillUnit:updateAlarmTriggers(alarmTriggers)
1069 for _, alarmTrigger in pairs(alarmTriggers) do
1070 self:setAlarmTriggerState(alarmTrigger, self:getAlarmTriggerIsActive(alarmTrigger))
1071 end
1072end

updateFillTypeMaterials

Description
Definition
updateFillTypeMaterials()
Code
1992function FillUnit:updateFillTypeMaterials(fillTypeMaterials, fillTypeIndex)
1993 for i=1, #fillTypeMaterials do
1994 local fillTypeMaterial = fillTypeMaterials[i]
1995 if fillTypeMaterial.fillTypeIndex == fillTypeIndex then
1996 local materialId = getMaterial(fillTypeMaterial.refNode, 0)
1997 setMaterial(fillTypeMaterial.node, materialId, 0)
1998 end
1999 end
2000end

updateFillUnitAutoAimTarget

Description
Definition
updateFillUnitAutoAimTarget()
Code
2004function FillUnit:updateFillUnitAutoAimTarget(fillUnit)
2005 local autoAimTarget = fillUnit.autoAimTarget
2006 if autoAimTarget.node ~= nil then
2007 if autoAimTarget.startZ ~= nil and autoAimTarget.endZ ~= nil then
2008 local startFillLevel = fillUnit.capacity * autoAimTarget.startPercentage
2009 local percent = MathUtil.clamp((fillUnit.fillLevel-startFillLevel) / (fillUnit.capacity-startFillLevel), 0, 1)
2010 if autoAimTarget.invert then
2011 percent = 1 - percent
2012 end
2013 local newZ = (autoAimTarget.endZ-autoAimTarget.startZ) * percent + autoAimTarget.startZ
2014 setTranslation(autoAimTarget.node, autoAimTarget.baseTrans[1], autoAimTarget.baseTrans[2], newZ)
2015 end
2016 end
2017end

updateFillUnitFillPlane

Description
Definition
updateFillUnitFillPlane()
Code
1920function FillUnit:updateFillUnitFillPlane(fillUnit)
1921 local fillPlane = fillUnit.fillPlane
1922 if fillPlane ~= nil then
1923 local t = self:getFillUnitFillLevelPercentage(fillUnit.fillUnitIndex)
1924
1925 for _, node in ipairs(fillPlane.nodes) do
1926 local x,y,z, rx,ry,rz, sx,sy,sz = node.animCurve:get(t)
1927
1928 setTranslation(node.node, x, y, z)
1929 setRotation(node.node, rx, ry, rz)
1930 setScale(node.node, sx, sy, sz)
1931 setVisibility(node.node, fillUnit.fillLevel > 0 or node.alwaysVisible)
1932 end
1933
1934 --assign new material on fill type change
1935 if fillUnit.fillType ~= fillUnit.lastFillPlaneType then
1936 if fillUnit.fillType ~= FillType.UNKNOWN then
1937 local usedFillType = fillUnit.fillType
1938 if fillPlane.forcedFillType ~= nil then
1939 usedFillType = fillPlane.forcedFillType
1940 end
1941
1942 local material = g_materialManager:getMaterial(usedFillType, "fillplane", 1)
1943 if material == nil and fillPlane.defaultFillType ~= nil then
1944 material = g_materialManager:getMaterial(fillPlane.defaultFillType, "fillplane", 1)
1945 end
1946
1947 if material ~= nil then
1948 for _, node in ipairs(fillPlane.nodes) do
1949 setMaterial(node.node, material, 0)
1950 end
1951 end
1952 end
1953
1954 fillUnit.lastFillPlaneType = fillUnit.fillType
1955 end
1956 end
1957end

updateFillUnitTriggers

Description
Definition
updateFillUnitTriggers()
Code
2067function FillUnit:updateFillUnitTriggers()
2068 local spec = self.spec_fillUnit
2069
2070 table.sort(spec.fillTrigger.triggers, function(t1, t2)
2071 local fillTypeIndex1 = t1:getCurrentFillType()
2072 local fillTypeIndex2 = t2:getCurrentFillType()
2073
2074 local t1FillUnitIndex = self:getFirstValidFillUnitToFill(fillTypeIndex1)
2075 local t2FillUnitIndex = self:getFirstValidFillUnitToFill(fillTypeIndex2)
2076
2077 if t1FillUnitIndex ~= nil and t2FillUnitIndex ~= nil then
2078 return self:getFillUnitFillLevel(t1FillUnitIndex) > self:getFillUnitFillLevel(t2FillUnitIndex)
2079 elseif t1FillUnitIndex ~= nil then
2080 return true
2081 end
2082
2083 return false
2084 end)
2085
2086 if #spec.fillTrigger.triggers > 0 then
2087 local fillTypeIndex = spec.fillTrigger.triggers[1]:getCurrentFillType()
2088 spec.fillTrigger.activatable:setFillType(fillTypeIndex)
2089
2090 if spec.fillTrigger.selectedTrigger ~= spec.fillTrigger.triggers[1] then
2091 SpecializationUtil.raiseEvent(self, "onFillUnitTriggerChanged", spec.fillTrigger.triggers[1], fillTypeIndex, self:getFirstValidFillUnitToFill(fillTypeIndex), #spec.fillTrigger.triggers)
2092
2093 spec.fillTrigger.selectedTrigger = spec.fillTrigger.triggers[1]
2094 end
2095 else
2096 spec.fillTrigger.selectedTrigger = nil
2097 end
2098end

updateMeasurementNodes

Description
Definition
updateMeasurementNodes()
Code
1790function FillUnit:updateMeasurementNodes(fillUnit, dt, setActive, forcedIntensity)
1791 if fillUnit.measurementNodes ~= nil then
1792 for _, measurementNode in pairs(fillUnit.measurementNodes) do
1793 if setActive ~= nil and setActive then
1794 measurementNode.measurementTime = 5000
1795 end
1796
1797 if measurementNode.measurementTime > 0 then
1798 measurementNode.measurementTime = math.max(measurementNode.measurementTime - dt, 0)
1799 end
1800
1801 local intensity = math.min(measurementNode.measurementTime / 5000, 1)
1802 intensity = math.max(intensity, math.min(self.lastSpeed * 3600 / 10, 1))
1803 intensity = forcedIntensity or intensity
1804 if intensity ~= measurementNode.intensity then
1805 setShaderParameter(measurementNode.node, "fillLevel", fillUnit.fillLevel / fillUnit.capacity, intensity, 0, 0, false)
1806 setShaderParameter(measurementNode.node, "prevFillLevel", fillUnit.fillLevel / fillUnit.capacity, measurementNode.intensity, 0, 0, false)
1807 measurementNode.intensity = intensity
1808 end
1809 end
1810 end
1811end

updateUnloadActionDisplay

Description
Definition
updateUnloadActionDisplay()
Code
2894function FillUnit.updateUnloadActionDisplay(self)
2895 local spec = self.spec_fillUnit
2896 if spec.unloading ~= nil then
2897 local isActive = false
2898 for k, fillUnit in ipairs(self:getFillUnits()) do
2899 local fillLevel = self:getFillUnitFillLevel(k)
2900 local fillTypeIndex = self:getFillUnitFillType(k)
2901 local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex)
2902 if fillUnit.canBeUnloaded and fillLevel > 0 and fillType.palletFilename ~= nil then
2903 isActive = true
2904 break
2905 end
2906 end
2907
2908 if self.getCurrentDischargeNode ~= nil then
2909 local dischargeNode = self:getCurrentDischargeNode()
2910 if dischargeNode ~= nil then
2911 local dischargeObject, _ = self:getDischargeTargetObject(dischargeNode)
2912 if dischargeObject ~= nil then
2913 isActive = false
2914 end
2915 end
2916 end
2917
2918 g_inputBinding:setActionEventActive(spec.unloadActionEventId, isActive)
2919 end
2920end