-- AD Load Swap -- En traktor der venter ved et Wait-punkt med en vare målet er fuldt af, mens målet -- MANGLER en anden vare i traktorens liste, låser forsyningen (alle venter med halm, -- ingen henter TMR). Her afleveres resten i en silo der tager varen, så vognen er tom -- og næste tur henter det målet mangler. ADLoadSwap = {} ADLoadSwap.LOG_PREFIX = "ADSmartPickup: " -- Opslaget går over alle markører; ventende traktorer tjekker derfor kun så tit. ADLoadSwap.CHECK_INTERVAL_MS = 5000 local warnedNoSilo = setmetatable({}, {__mode = "k"}) -- Er en anden vare i listen så tom i målet, at et FULDT læs passer, og findes den i en silo? function ADLoadSwap.findMissingIngredient(adEnv, vehicle, restFillType) local ingredients = ADSmartPickup.getIngredientsFor(adEnv, vehicle) if ingredients == nil or #ingredients < 2 then return nil end local choice = ADSmartPickup.findSupplyPickup(adEnv, vehicle, ingredients) if choice == nil or choice.fillType == nil or choice.fillType == restFillType or choice.need.fits ~= true then return nil end return choice end -- Kun rene lager-siloer: stalde og fabrikker har egne regler, og målet selv er fuldt. local function isSilo(station, homeStation) local placeable = station.owningPlaceable return placeable ~= nil and placeable.spec_silo ~= nil and placeable.getHusbandryFillLevel == nil and placeable.spec_productionPoint == nil and (homeStation == nil or placeable ~= homeStation.owningPlaceable) end local function acceptsRest(station, fillType, rest, farmId) if station.getIsFillTypeSupported ~= nil and not station:getIsFillTypeSupported(fillType) then return false end local free = station.getFreeCapacity ~= nil and station:getFreeCapacity(fillType, farmId) or 0 return free >= rest end -- Nærmeste silo med plads til resten og vejnet til/fra; siloer der allerede har varen foretrækkes. function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointId, isReachable) if vehicle.rootNode == nil then return nil end local farmId = ADSmartPickup.getFarmId(vehicle) local homeStation = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, homeWayPointId, farmId) local x, _, z = getWorldTranslation(vehicle.rootNode) local candidates = {} for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId) if station ~= nil and isSilo(station, homeStation) and acceptsRest(station, fillType, rest, farmId) then local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id) -- En markør uden waypoint (stale AD-graf) skal springes over, ikke crashe hele opslaget. if wayPoint ~= nil then local dx, dz = wayPoint.x - x, wayPoint.z - z table.insert(candidates, { marker = marker, hasFillType = ADSmartPickup.getOwnStorageLevel(station, {fillType}) > 0, distance = dx * dx + dz * dz, }) end end end table.sort(candidates, function(a, b) if a.hasFillType ~= b.hasFillType then return a.hasFillType end return a.distance < b.distance end) for _, candidate in ipairs(candidates) do if isReachable(candidate.marker.id) then return candidate.marker end end return nil end -- Kaldes fra Wait-logikken hvert tick; redirect(task, id) og release(vehicle) er dens egne. -- true = traktoren er sendt til en silo (Wait-punktet er frigivet). function ADLoadSwap.tryFromWait(adEnv, task, wait, dt, redirect, release, isReachable) wait.swapTimerMs = (wait.swapTimerMs or 0) + (dt or 0) if wait.swapTimerMs < ADLoadSwap.CHECK_INTERVAL_MS then return false end wait.swapTimerMs = 0 local vehicle = task.vehicle -- Tager målet slet ikke varen (forkert last), skal den af uanset hvad der ellers mangler. local missing = ADLoadSwap.findMissingIngredient(adEnv, vehicle, wait.fillType) if missing == nil and not wait.isRejected then return false end local marker = ADLoadSwap.findDumpMarker(adEnv, vehicle, wait.fillType, wait.rest, wait.homeDestinationID, isReachable) local restName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(wait.fillType) or tostring(wait.fillType) local missingName = missing ~= nil and (g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(missing.fillType) or tostring(missing.fillType)) or "-" if marker == nil then if not warnedNoSilo[vehicle] then warnedNoSilo[vehicle] = true Logging.warning(ADLoadSwap.LOG_PREFIX .. "'%s' venter med %.0f l %s, og målet mangler %s — ingen silo med plads og vejnet til/fra tager resten, så den bliver ved Wait-punktet", tostring(vehicle:getName()), wait.rest, tostring(restName), tostring(missingName)) end return false end warnedNoSilo[vehicle] = nil release(vehicle) redirect(task, marker.id) local why = missing ~= nil and ("målet mangler " .. tostring(missingName)) or "målet tager ikke varen" Logging.info(ADLoadSwap.LOG_PREFIX .. "'%s' bytter læs: %.0f l %s tilbage i %s (markør %s), %s", tostring(vehicle:getName()), wait.rest, tostring(restName), tostring(marker.name), tostring(marker.markerIndex or marker.id), why) return true end function ADLoadSwap.clearWarning(vehicle) warnedNoSilo[vehicle] = nil end