-- AD Field Silos -- Marksilo-flowet i spillet: samler marksiloer, gårdlagre og ledige vogne, lader ADFieldSiloPlanner vælge, -- med "kør til produktion" går overskud ud over gårdens foderreserve til gårdens fabrikker; -- låner vogne (AutoDrive "Hent og aflever", én tur, parkering bagefter) og frigiver dem igen. -- Lån ligger kun i hukommelsen; opsætningen gemmes i ADSmartPickup_fieldsilos.xml. ADFieldSilos = {} ADFieldSilos.PLAN_INTERVAL_MS = 60000 ADFieldSilos.CHECK_INTERVAL_MS = 2000 ADFieldSilos.STUCK_MS = 120000 ADFieldSilos.PAUSE_MS = 600000 ADFieldSilos.FAIL_MS = 30000 -- AD slukket inden for 30 s uden fremdrift = turen kunne ikke køres ADFieldSilos.CARGO_MIN_LITERS = 100 -- rest under dette tæller ikke som last -- Silo så tæt på et gårdlager er en del af gården (Farma-siloer deler lager inden for 50 m): ikke marksilo. -- (in-game 27/9: sukkerroer blev kørt fra én Farma-silo til nabosiloen i samme klynge) ADFieldSilos.FARM_RADIUS = 100 -- Siloer højst så langt fra en nabo hører til samme klynge (Farma-rækker: 15 m mellem siloer, 18 m mellem rækker) ADFieldSilos.CLUSTER_LINK = 60 ADFieldSilos.MOVING_SPEED = 0.00028 -- m/ms, samme grænse som AutoDrive ADFieldSilos.FILE_NAME = "ADSmartPickup_fieldsilos.xml" ADFieldSilos.ROOT = "ADSmartPickupFieldSilos" ADFieldSilos.LOG_PREFIX = "ADSmartPickup: marksilo: " ADFieldSilos.config = ADFieldSiloConfig.new() ADFieldSilos.lastPlan = nil local loans = setmetatable({}, {__mode = "k"}) -- vehicle -> {siloId, siloName, fillType, liters, startedMs, lastProgressMs, lastFill} local paused = {} -- key -> untilMs local planTimerMs, checkTimerMs, nowMs = ADFieldSilos.PLAN_INTERVAL_MS, 0, 0 -- ---- ren frigivelsesregel ---- -- vehicleState = {adActive, controlled, fill, moving}. Fremdrift = kører, eller fyldningen ændrer sig (læsser -- eller aflæsser). Vagten gælder kun før turen er kommet i gang — kø ved siloen/lageret er normalt. function ADFieldSilos.releaseReason(loan, vehicleState, now) if vehicleState.controlled then return "player" end local progressing = vehicleState.moving or (vehicleState.fill or 0) ~= (loan.lastFill or 0) local hasProgressed = loan.hasProgressed or progressing local age = now - (loan.startedMs or 0) if not vehicleState.adActive then return (not hasProgressed and age < ADFieldSilos.FAIL_MS) and "failed" or "done" end if hasProgressed then return nil end if age > ADFieldSilos.STUCK_MS then return "stuck" end return nil end -- ---- opsætning ---- function ADFieldSilos.setConfig(cfg) local wasEnabled = ADFieldSilos.config.enabled ADFieldSilos.config = cfg if wasEnabled and not cfg.enabled then ADFieldSilos.stopAll(ADFieldSilos.adEnv) end planTimerMs = ADFieldSilos.PLAN_INTERVAL_MS -- planlæg straks ved næste tick end function ADFieldSilos.isLoaned(vehicle) return loans[vehicle] ~= nil end function ADFieldSilos.loanCount() local n = 0 for _ in pairs(loans) do n = n + 1 end return n end -- ---- spil-input ---- local function farmId() return g_currentMission ~= nil and g_currentMission.getFarmId ~= nil and g_currentMission:getFarmId() or 1 end local function position(node) if node == nil then return 0, 0 end local x, _, z = getWorldTranslation(node) return x, z end local function siloStock(placeable) local stock = {} local spec = placeable ~= nil and placeable.spec_silo or nil for _, storage in pairs(spec ~= nil and spec.storages or {}) do for fillType, level in pairs(storage.fillLevels or {}) do if (level or 0) > 0 then stock[fillType] = (stock[fillType] or 0) + level end end end return stock end local function siloFree(placeable) local free = {} local spec = placeable ~= nil and placeable.spec_silo or nil for _, storage in pairs(spec ~= nil and spec.storages or {}) do for fillType in pairs(storage.fillTypes or {}) do local amount = storage.getFreeCapacity ~= nil and (storage:getFreeCapacity(fillType) or 0) or 0 free[fillType] = (free[fillType] or 0) + amount end end return free end local function firstMarker(building, role) local markers = ADBuildings.getMarkers(building, role) return markers[1] ~= nil and markers[1].id or nil end -- Bygninger der er kilde, mål eller lager i et flow: dem tømmer marksilo-flowet ikke (de hører til den drift). local function runBuildingIds() local ids = {} local store = ADRunsController ~= nil and ADRunsController.store or nil for _, run in ipairs(store ~= nil and store.runs or {}) do for _, list in ipairs({run.sourceBuildingIds or {}, run.targetBuildingIds or {}, run.storeBuildingIds or {}}) do for _, id in ipairs(list) do ids[id] = true end end end return ids end -- Alle siloer i samme klynge som et gårdlager (kæde af naboer ≤ CLUSTER_LINK): gårdens, aldrig marksiloer. -- (in-game 27/9: gårdens Farma-klynge er ~300 m lang; siloer over 100 m fra et valgt lager blev marksiloer) local function farmCluster(allSilos, storeIds) local farm, queue = {}, {} for _, silo in ipairs(allSilos) do if storeIds[silo.id] then farm[silo.id] = true; table.insert(queue, silo) end end local link2 = ADFieldSilos.CLUSTER_LINK ^ 2 while #queue > 0 do local current = table.remove(queue) for _, silo in ipairs(allSilos) do if not farm[silo.id] and (silo.x - current.x) ^ 2 + (silo.z - current.z) ^ 2 <= link2 then farm[silo.id] = true table.insert(queue, silo) end end end return farm end local function nearStore(stores, x, z) for _, store in ipairs(stores) do if (store.x - x) ^ 2 + (store.z - z) ^ 2 <= ADFieldSilos.FARM_RADIUS ^ 2 then return true end end return false end -- Fabrikkens input-varer (dem aflæsningen tager imod) med fri plads i dens lager. local function factoryFree(placeable) local spec = placeable ~= nil and placeable.spec_productionPoint or nil local point = spec ~= nil and spec.productionPoint or nil local storage = point ~= nil and point.storage or nil if storage == nil or storage.getFreeCapacity == nil then return {} end local inputs = {} for fillType in pairs(point.inputFillTypeIds or {}) do inputs[fillType] = true end for _, production in ipairs(point.productions or {}) do for _, input in ipairs(production.inputs or {}) do inputs[input.type] = true end end local free = {} for fillType in pairs(inputs) do free[fillType] = storage:getFreeCapacity(fillType) or 0 end return free end -- "Kør til produktion": gårdens fabrikker med aflæsningsmarkør bliver mål ved siden af gårdlagrene. local function addFactories(stores, buildings) for _, building in ipairs(buildings) do local markerId = building.kind == "factory" and firstMarker(building, "unload") or nil if markerId ~= nil then local x, z = position(building.placeable ~= nil and building.placeable.rootNode or nil) table.insert(stores, {id = building.id, name = building.name, kind = "production", markerId = markerId, x = x, z = z, free = factoryFree(building.placeable)}) end end end -- Foderreserve (staldenes døgnforbrug × døgn) og gårdlagrenes beholdning pr. vare. function ADFieldSilos.collectFeed(stores, byId, fid, reserveDays) local reserve, stock = {}, {} local rates = ADSources ~= nil and ADSources.getFarmRates ~= nil and ADSources.getFarmRates(ADFieldSilos.adEnv, fid, true) or {} for fillType, rate in pairs(rates) do reserve[fillType] = (rate.consumption or 0) * reserveDays end local counted = {} -- Farma-siloer i samme klynge deler lager: tæl hvert lager én gang for _, store in ipairs(stores) do local building = byId[store.id] local spec = store.kind ~= "production" and building ~= nil and building.placeable ~= nil and building.placeable.spec_silo or nil for _, storage in pairs(spec ~= nil and spec.storages or {}) do if not counted[storage] then counted[storage] = true for fillType, level in pairs(storage.fillLevels or {}) do stock[fillType] = (stock[fillType] or 0) + (level or 0) end end end end return reserve, stock end -- Gårdlagre fra opsætningen + marksiloer (alle markers marksiloer, uden dubletter og uden gårdlagre). function ADFieldSilos.collectBuildings(adEnv) local fid = farmId() local stores, byId, allSilos, storeIds = {}, {}, {}, {} for _, building in ipairs(ADBuildings.list(adEnv, fid)) do byId[building.id] = building if building.kind == "silo" then local sx, sz = position(building.placeable ~= nil and building.placeable.rootNode or nil) table.insert(allSilos, {id = building.id, x = sx, z = sz}) if ADFieldSiloConfig.hasStore(ADFieldSilos.config, building.id) then storeIds[building.id] = true end end if building.kind == "silo" and ADFieldSiloConfig.hasStore(ADFieldSilos.config, building.id) then local x, z = position(building.placeable ~= nil and building.placeable.rootNode or nil) table.insert(stores, {id = building.id, name = building.name, markerId = firstMarker(building, "unload"), x = x, z = z, free = siloFree(building.placeable)}) end end if ADFieldSilos.config.toProduction then addFactories(stores, ADBuildings.list(adEnv, fid)) end local silos, seen = {}, runBuildingIds() for id in pairs(farmCluster(allSilos, storeIds)) do seen[id] = true end for _, info in ipairs(ADFields.list()) do for _, building in ipairs(ADFields.fieldSilos(adEnv, fid, info)) do local x, z = position(building.placeable ~= nil and building.placeable.rootNode or nil) if not seen[building.id] and not ADFieldSiloConfig.hasStore(ADFieldSilos.config, building.id) and not nearStore(stores, x, z) then seen[building.id] = true -- marknummeret først: navnet skæres af i fanen, og mange siloer hedder ens ("Farma 500 …") -- marknummeret først (medmindre navnet allerede starter med det, fx "F22 marksilo") local siloName = tostring(building.name) if not siloName:match("^F" .. tostring(info.id) .. "%f[%D]") then siloName = string.format("F%s %s", tostring(info.id), siloName) end table.insert(silos, {id = building.id, name = siloName, markerId = firstMarker(building, "load"), x = x, z = z, stock = siloStock(building.placeable)}) end end end return silos, stores, byId end local function trailerInfo(adEnv, vehicle) local capacity, carries, cargo = 0, {}, nil for _, unit in ipairs(adEnv.AutoDrive.getAllDischargeableUnits(vehicle) or {}) do local object, index = unit.object, unit.fillUnitIndex if object ~= nil and object.getFillUnitCapacity ~= nil then capacity = capacity + (object:getFillUnitCapacity(index) or 0) for fillType in pairs(object.getFillUnitSupportedFillTypes ~= nil and object:getFillUnitSupportedFillTypes(index) or {}) do carries[fillType] = true end if (object:getFillUnitFillLevel(index) or 0) >= ADFieldSilos.CARGO_MIN_LITERS then cargo = object:getFillUnitFillType(index) end end end return capacity, carries, cargo end local function fillLevel(adEnv, vehicle) local ok, level = pcall(function() return (adEnv.AutoDrive.getAllFillLevels(adEnv.AutoDrive.getAllUnits(vehicle))) end) return ok and tonumber(level) or 0 end function ADFieldSilos.collectVehicles(adEnv) local vehicles, byId = {}, {} -- hvorfor tømmevogne ikke kan lånes (til fanens statuslinje) local why = {notEnabled = 0, busy = 0, controlled = 0, noPark = 0} local rigs = ADFieldWork.getRigs(adEnv) for _, rig in ipairs(rigs) do -- uden AD-parkeringspunkt bliver vognen holdende på lagerets markør og spærrer for de næste local canPark = ADFieldWork.parkMarkerId == nil or ADFieldWork.parkMarkerId(adEnv, rig.vehicle) ~= nil if rig.role == "unloader" then if not rig.enabled then why.notEnabled = why.notEnabled + 1 elseif rig.controlled then why.controlled = why.controlled + 1 elseif rig.busy then why.busy = why.busy + 1 elseif not canPark then why.noPark = why.noPark + 1 end end if rig.role == "unloader" and rig.enabled and not rig.busy and not rig.controlled and canPark then local capacity, carries, cargo = trailerInfo(adEnv, rig.vehicle) table.insert(vehicles, {id = rig.id, x = rig.x, z = rig.z, capacity = capacity, carries = carries, cargo = cargo}) byId[rig.id] = rig.vehicle end end local ok, needs = pcall(ADFieldSilos.harvestNeeds, adEnv, rigs) if ok and #needs > 0 then local before = #vehicles vehicles = ADFieldSiloPlanner.withoutHarvestReserve(vehicles, needs) why.harvest = before - #vehicles elseif not ok then Logging.warning(ADFieldSilos.LOG_PREFIX .. "høstreserve kunne ikke beregnes: %s", tostring(needs)) end why.eligible = #vehicles ADFieldSilos.lastVehicleReasons = why return vehicles, byId end -- Høsten først: pr. høster der arbejder (CP kører) holdes dens planlagte antal tømmevogne tilbage, minus dem -- markarbejdet allerede har sendt til marken. (in-game 28/9: marksilo-flowet havde lånt begge kartoffelvogne, -- og ingen kom til roeoptagerne.) function ADFieldSilos.harvestNeeds(adEnv, rigs) local assignments = ADFieldJobs ~= nil and ADFieldJobs.state ~= nil and ADFieldJobs.state.assignments or {} local sent = {} for _, assignment in pairs(assignments) do if assignment.role == "unloader" and assignment.fieldId ~= nil then sent[assignment.fieldId] = (sent[assignment.fieldId] or 0) + 1 end end local needs = {} for _, rig in ipairs(rigs) do if rig.role == "harvester" and ADCpBridge.isWorking(rig.vehicle) then local assignment = assignments[rig.id] local fieldId = assignment ~= nil and assignment.fieldId or nil local field = fieldId ~= nil and ADFieldJobs.getField(fieldId) or nil local info = fieldId ~= nil and ADFields.getInfo(fieldId) or nil local count = field ~= nil and ADFieldModel.maxHelpers("harvesting", field.plan) or 1 count = count - (fieldId ~= nil and (sent[fieldId] or 0) or 0) local fillTypes = {} if info ~= nil and info.harvestFillType ~= nil then fillTypes[info.harvestFillType] = true else for fruitIndex in pairs(rig.fruits or {}) do local fruit = g_fruitTypeManager ~= nil and g_fruitTypeManager:getFruitTypeByIndex(fruitIndex) or nil if fruit ~= nil and fruit.fillType ~= nil then fillTypes[fruit.fillType.index] = true end end end for fillType in pairs(fillTypes) do if count > 0 then table.insert(needs, {fillType = fillType, count = count}) end end end end return needs end -- ---- lån ---- local function fillTypeName(fillType) local desc = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeByIndex(fillType) or nil return desc ~= nil and (desc.title or desc.name) or tostring(fillType) end local function dispatchOne(adEnv, order, vehicle, silosById, storesById) local module = vehicle.ad.stateModule module:setMode(adEnv.AutoDrive.MODE_PICKUPANDDELIVER) module:setFirstMarkerByWayPointId(order.siloMarkerId) module:setSecondMarkerByWayPointId(order.storeMarkerId) module.selectedFillTypes = {order.fillType} module:setFillType(order.fillType) module.loopCounter = 1 if module.setLoopsDone ~= nil then module:setLoopsDone(0) end ADFieldWork.enableParkAtJobFinished(vehicle) -- rotation fra: ellers kan modens egne pickup-hooks sende vognen til en anden silo i mappen if ADRunsController ~= nil and ADRunsController.setSetting ~= nil then ADRunsController.setSetting(adEnv, vehicle, "rotateTargets", adEnv.AutoDrive.RT_NONE) end module:raiseDirtyFlag() ADFieldWork.startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_PICKUPANDDELIVER, order.siloMarkerId, order.storeMarkerId, order.fillType) local silo, store = silosById[order.siloId], storesById[order.storeId] loans[vehicle] = {siloId = order.siloId, storeId = order.storeId, siloName = silo ~= nil and silo.name or order.siloId, fillType = order.fillType, liters = order.liters, startedMs = nowMs, lastProgressMs = nowMs, lastFill = fillLevel(adEnv, vehicle)} Logging.info(ADFieldSilos.LOG_PREFIX .. "'%s' henter %d l %s i %s -> %s", tostring(ADRuns.vehicleLabel(vehicle)), math.floor(order.liters), fillTypeName(order.fillType), tostring(silo ~= nil and silo.name or order.siloId), tostring(store ~= nil and store.name or order.storeId)) end local function release(adEnv, vehicle, reason) local loan = loans[vehicle] loans[vehicle] = nil if loan == nil then return end if reason == "stuck" or reason == "failed" then local k = ADFieldSiloPlanner.key(loan.siloId, loan.fillType) paused[k] = nowMs + ADFieldSilos.PAUSE_MS pcall(vehicle.stopAutoDrive, vehicle) local why = reason == "stuck" and "kom ikke i gang på 2 min — stoppet" or "AutoDrive stoppede turen med det samme (rute/læssested?)" Logging.warning(ADFieldSilos.LOG_PREFIX .. "'%s' ved %s (%s): %s; siloen springes over i 10 min", tostring(ADRuns.vehicleLabel(vehicle)), tostring(loan.siloName), fillTypeName(loan.fillType), why) elseif reason == "stopped" then pcall(vehicle.stopAutoDrive, vehicle) end Logging.info(ADFieldSilos.LOG_PREFIX .. "'%s' frigivet (%s)", tostring(ADRuns.vehicleLabel(vehicle)), tostring(reason)) end function ADFieldSilos.stopAll(adEnv) local list = {} for vehicle in pairs(loans) do table.insert(list, vehicle) end for _, vehicle in ipairs(list) do release(adEnv, vehicle, "stopped") end end local function checkLoans(adEnv) local list = {} for vehicle in pairs(loans) do table.insert(list, vehicle) end for _, vehicle in ipairs(list) do if vehicle.isDeleted then loans[vehicle] = nil -- solgt/slettet mens den var lånt else local ok, err = pcall(function() local loan = loans[vehicle] local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil local fill = fillLevel(adEnv, vehicle) local vehicleState = { adActive = stateModule ~= nil and stateModule:isActive(), controlled = vehicle.getIsControlled ~= nil and vehicle:getIsControlled() or false, fill = fill, moving = (vehicle.lastSpeedReal or 0) >= ADFieldSilos.MOVING_SPEED, } local reason = ADFieldSilos.releaseReason(loan, vehicleState, nowMs) if vehicleState.moving or fill ~= (loan.lastFill or 0) then loan.hasProgressed = true end loan.lastFill = fill if reason ~= nil then release(adEnv, vehicle, reason) end end) if not ok then loans[vehicle] = nil Logging.warning(ADFieldSilos.LOG_PREFIX .. "lån opgivet (fejl): %s", tostring(err)) end end end end local function currentPaused() local result = {} for k, untilMs in pairs(paused) do if untilMs > nowMs then result[k] = true else paused[k] = nil end end return result end local function loanList() local list = {} for _, loan in pairs(loans) do table.insert(list, {siloId = loan.siloId, storeId = loan.storeId, fillType = loan.fillType, liters = loan.liters}) end return list end -- Rute fra vognen til siloen og videre til lageret (samme opslag som Wait-punkterne); én advarsel pr. kombination. local warnedRoute = {} local function hasRoutes(adEnv, vehicle, order) if ADUnloadWait == nil or ADUnloadWait.hasRouteTo == nil then return true end local ok = ADUnloadWait.hasRouteTo(adEnv, vehicle, order.siloMarkerId) and ADUnloadWait.hasRouteTo(adEnv, vehicle, order.storeMarkerId) local warnKey = tostring(order.vehicleId) .. ">" .. tostring(order.siloMarkerId) if not ok and not warnedRoute[warnKey] then warnedRoute[warnKey] = true Logging.warning(ADFieldSilos.LOG_PREFIX .. "ingen AutoDrive-rute for '%s' til marksilo-markør %s eller gårdlager-markør %s", tostring(ADRuns.vehicleLabel(vehicle)), tostring(order.siloMarkerId), tostring(order.storeMarkerId)) end return ok end function ADFieldSilos.planNow(adEnv) local cfg = ADFieldSilos.config local silos, stores, byId = ADFieldSilos.collectBuildings(adEnv) local vehicles, vehiclesById = ADFieldSilos.collectVehicles(adEnv) local feedReserve, farmStock = nil, nil if cfg.toProduction then local ok, reserve, stock = pcall(ADFieldSilos.collectFeed, stores, byId, farmId(), cfg.reserveDays) if ok then feedReserve, farmStock = reserve, stock else Logging.warning(ADFieldSilos.LOG_PREFIX .. "foderreserve kunne ikke beregnes: %s", tostring(reserve)) end end local plan = ADFieldSiloPlanner.plan({silos = silos, stores = stores, loans = loanList(), vehicles = vehicles, paused = currentPaused(), maxVehicles = cfg.maxVehicles, minLiters = cfg.minLiters, feedReserve = feedReserve, farmStock = farmStock}) ADFieldSilos.lastFeed = {reserve = feedReserve, stock = farmStock} ADFieldSilos.lastPlan = plan local paused = ADFieldJobs ~= nil and ADFieldJobs.state ~= nil and ADFieldJobs.state.paused if not cfg.enabled or paused then return plan end local silosById, storesById = {}, {} for _, silo in ipairs(silos) do silosById[silo.id] = silo end for _, store in ipairs(stores) do storesById[store.id] = store end for _, order in ipairs(plan.dispatch) do local vehicle = vehiclesById[order.vehicleId] if vehicle ~= nil and not hasRoutes(adEnv, vehicle, order) then vehicle = nil end if vehicle ~= nil then local ok, err = pcall(dispatchOne, adEnv, order, vehicle, silosById, storesById) if not ok then loans[vehicle] = nil Logging.warning(ADFieldSilos.LOG_PREFIX .. "kunne ikke sende '%s': %s", tostring(ADRuns.vehicleLabel(vehicle)), tostring(err)) end end end return plan end function ADFieldSilos.tick(adEnv, dt) if adEnv == nil then return end ADFieldSilos.adEnv = adEnv nowMs = nowMs + (dt or 0) checkTimerMs = checkTimerMs + (dt or 0) if checkTimerMs >= ADFieldSilos.CHECK_INTERVAL_MS then checkTimerMs = 0 checkLoans(adEnv) end planTimerMs = planTimerMs + (dt or 0) if planTimerMs >= ADFieldSilos.PLAN_INTERVAL_MS then planTimerMs = 0 ADFieldSilos.planNow(adEnv) end end -- ---- gem / indlæs (samme sti-opslag som runs) ---- local function getPath() local path = ADRunsStorage ~= nil and ADRunsStorage.getPath() or nil if path == nil then return nil end return (path:gsub(ADRunsStorage.FILE_NAME .. "$", ADFieldSilos.FILE_NAME)) end function ADFieldSilos.save() local path = getPath() if path == nil then return false end local xmlFile = XMLFile.create("ADSmartPickupFieldSilos", path, ADFieldSilos.ROOT) if xmlFile == nil then return false end local record = ADFieldSiloConfig.toRecord(ADFieldSilos.config) xmlFile:setInt(ADFieldSilos.ROOT .. "#enabled", record.enabled) xmlFile:setString(ADFieldSilos.ROOT .. "#stores", record.stores) xmlFile:setInt(ADFieldSilos.ROOT .. "#maxVehicles", record.maxVehicles) xmlFile:setInt(ADFieldSilos.ROOT .. "#minLiters", record.minLiters) xmlFile:setInt(ADFieldSilos.ROOT .. "#toProduction", record.toProduction) xmlFile:setInt(ADFieldSilos.ROOT .. "#reserveDays", record.reserveDays) xmlFile:save() xmlFile:delete() return true end function ADFieldSilos.load() local path = getPath() if path == nil or not fileExists(path) then ADFieldSilos.config = ADFieldSiloConfig.new() return end local xmlFile = XMLFile.load("ADSmartPickupFieldSilos", path) if xmlFile == nil then ADFieldSilos.config = ADFieldSiloConfig.new() return end ADFieldSilos.config = ADFieldSiloConfig.fromRecord({ enabled = xmlFile:getInt(ADFieldSilos.ROOT .. "#enabled"), stores = xmlFile:getString(ADFieldSilos.ROOT .. "#stores"), maxVehicles = xmlFile:getInt(ADFieldSilos.ROOT .. "#maxVehicles"), minLiters = xmlFile:getInt(ADFieldSilos.ROOT .. "#minLiters"), toProduction = xmlFile:getInt(ADFieldSilos.ROOT .. "#toProduction"), reserveDays = xmlFile:getInt(ADFieldSilos.ROOT .. "#reserveDays"), }) xmlFile:delete() end