-- Kør: luajit tests/test_adBuildings.lua (fra repo-roden) -- Bygninger gården kan bruge + automatisk markør ved læsse-/aflæsningstrigger (≤ 40 m, Wait udelukket, -- siloer strengt), omvendt opslag markør -> bygning, id-fallback, cache. local SUGAR, FORAGE, MILK, BASKET = 5, 6, 12, 7 local DESC = {[SUGAR] = {name = "SUGAR", title = "Sukker", isPalletType = true}, [FORAGE] = {name = "FORAGE", title = "TMR"}, [MILK] = {name = "MILK", title = "Mælk"}, [BASKET] = {name = "STRAW_BASKET", title = "Kurve", palletFilename = "x"}} g_fillTypeManager = {getFillTypeByIndex = function(_, i) return DESC[i] end, getFillTypeNameByIndex = function(_, i) return DESC[i] and DESC[i].name end, getFillTypeTitleByIndex = function(_, i) return DESC[i] and DESC[i].title end} Logging = {info = function() end, warning = function() end} getWorldTranslation = function(node) return node.x, 0, node.z end SellingStation = {} dofile("FS25_ADSmartPickup/adSupplyPlanner.lua") dofile("FS25_ADSmartPickup/adPrices.lua") dofile("FS25_ADSmartPickup/adBuildings.lua") local failures = 0 local function check(name, actual, expected) if actual == expected then print("OK " .. name) else failures = failures + 1; print(string.format("FAIL %s: forventede %s, fik %s", name, tostring(expected), tostring(actual))) end end local markers, wayPoints = {}, {} local function addMarker(id, name, group, x, z) wayPoints[id] = {id = id, x = x, z = z} table.insert(markers, {id = id, markerIndex = #markers + 1, name = name, group = group}) end local loadStations, unloadStations = {}, {} local adEnv = {ADGraphManager = { getWayPointById = function(_, id) return wayPoints[id] end, getMapMarkers = function() return markers end, getMapMarkerByWayPointId = function(_, id) for _, m in ipairs(markers) do if m.id == id then return m end end end, }} local strictLoadAt = {} ADSmartPickup = {getLoadStationAtWayPointId = function(_, id) return strictLoadAt[id] end} g_currentMission = { placeableSystem = {placeables = {}}, storageSystem = {getLoadingStations = function() return loadStations end, getUnloadingStations = function() return unloadStations end}, accessHandler = {canFarmAccess = function() return true end}, getFarmId = function() return 1 end, } local function placeable(uid, name, x, z, extra) local p = {uniqueId = uid, rootNode = {x = x, z = z}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return name end} for k, v in pairs(extra or {}) do p[k] = v end table.insert(g_currentMission.placeableSystem.placeables, p) return p end -- verden: kostald med mælketank (load) og foder (unload), sukkerfabrik (unload + pallespawner), to siloer i række, objektlager, salgssted local barn = placeable("barn1", "Kostald 1", 0, 0, {getHusbandryFillLevel = function() return 0 end}) -- som FS25_LargerAnimalBarns' cowBarnBig: ÉN læssestation med TO læssepunkter (gylle + mælk) local milkStation = {owningPlaceable = barn, loadTriggers = {{triggerNode = {x = 20, z = 0}}, {triggerNode = {x = 0, z = 30}}}} local barnUnload = {owningPlaceable = barn, unloadTriggers = {{exactFillRootNode = {x = -20, z = 0}}}} table.insert(loadStations, milkStation); table.insert(unloadStations, barnUnload) local mill = placeable("mill", "Sukkerfabrik", 500, 0, {spec_productionPoint = {productionPoint = {productions = {}, storage = {}, palletSpawner = {spawnPlaces = {{startNode = {x = 520, z = 0}}}}, unloadingStation = nil}}}) local millUnload = {owningPlaceable = mill, unloadTriggers = {{exactFillRootNode = {x = 480, z = 0}}}, isa = function() return true end, isSellingPoint = true} table.insert(unloadStations, millUnload) local silo1 = placeable("silo1", "Silo 1", 1000, 0, {spec_silo = {}}) local silo2 = placeable("silo2", "Silo 2", 1015, 0, {spec_silo = {}}) local silo1Station = {owningPlaceable = silo1, loadTriggers = {{triggerNode = {x = 1000, z = 5}}}} local silo2Station = {owningPlaceable = silo2, loadTriggers = {{triggerNode = {x = 1015, z = 5}}}} table.insert(loadStations, silo1Station); table.insert(loadStations, silo2Station) table.insert(unloadStations, {owningPlaceable = silo1, unloadTriggers = {{exactFillRootNode = {x = 1000, z = 5}}}}) table.insert(unloadStations, {owningPlaceable = silo2, unloadTriggers = {{exactFillRootNode = {x = 1015, z = 5}}}}) local shed = placeable("shed", "Palleskur", 2000, 0, {spec_objectStorage = {objectInfos = {}, capacity = 100}}) local sellPoint = placeable("sell", "Mejeri", 3000, 0, {}) local sellStation = {owningPlaceable = sellPoint, unloadTriggers = {{exactFillRootNode = {x = 3000, z = 10}}}, isa = function() return true end, isSellingPoint = true} table.insert(unloadStations, sellStation) local other = placeable("otherfarm", "Naboens", 4000, 0, {spec_silo = {}, ownerFarmId = 2, getOwnerFarmId = function() return 2 end}) addMarker(1, "cow 1 milk", "Milk", 25, 0) -- 5 m fra mælketriggeren addMarker(2, "Cow 1 food", "Cow food", -30, 0) -- 10 m fra fodertriggeren addMarker(3, "cow wait 1", "cow wait", 22, 0) -- Wait: må ALDRIG vælges (tættere end mælkemarkøren) addMarker(11, "Cow 1 Slurry", "Slurry", 0, 33) -- 3 m fra gylletriggeren addMarker(4, "Suger Load", "Pickup", 525, 0) -- 5 m fra pallespawneren addMarker(5, "sugar offload", "production", 470, 0) addMarker(6, "silo 1", "silo", 1000, 12) -- strengt: silo1 addMarker(7, "silo 2", "silo", 1015, 12) -- strengt: silo2 (7 m fra silo1's trigger-node på x-aksen? nej: 15 m) strictLoadAt[6] = silo1Station; strictLoadAt[7] = silo2Station addMarker(8, "Storage pickup", "Pickup", 2010, 0) addMarker(9, "Mejeri", "selling", 3000, 20) addMarker(10, "Langt væk", "All", 9000, 9000) -- B1: liste, kind og markører local list = ADBuildings.list(adEnv, 1) local byId = {} for _, b in ipairs(list) do byId[b.id] = b end check("B1 antal (naboens silo udeladt)", #list, 6) check("B1 stald", byId.barn1.kind, "husbandry") check("B1 stald læssemarkør = mælk (ikke Wait, som er tættere)", byId.barn1.loadMarker.id, 1) -- én markør pr. læssestation (mælketank OG gyllebeholder), sorteret på markørnavn check("B1 stald har to læssemarkører", #byId.barn1.loadMarkers, 2) check("B1 første = cow 1 milk (navnesorteret, uanset store/små)", byId.barn1.loadMarkers[1].id, 1) check("B1 anden = Cow 1 Slurry", byId.barn1.loadMarkers[2].name, "Cow 1 Slurry") check("B1 gyllemarkør -> stald via byMarker", ADBuildings.byMarker(adEnv, 1, 11, "load").id, "barn1") check("B1 stald aflæsningsmarkør = foder", byId.barn1.unloadMarker.id, 2) check("B1 stald afstand", byId.barn1.loadMarker.distance, 5) check("B1 fabrik læssemarkør via pallespawner", byId.mill.loadMarker.id, 4) check("B1 fabrik aflæsningsmarkør", byId.mill.unloadMarker.id, 5) check("B1 fabrik er ikke salgssted", byId.mill.canSell, false) check("B1 objektlager markør via rootNode", byId.shed.loadMarker.id, 8) check("B1 salgssted", byId.sell.kind, "sell") check("B1 salgssted markør", byId.sell.unloadMarker.id, 9) check("B1 salgssted canSell", byId.sell.canSell, true) check("B1 stald kan være kilde og mål", byId.barn1.canBeSource and byId.barn1.canBeTarget, true) check("B1 silo kilde, ikke mål", byId.silo1.canBeSource and not byId.silo1.canBeTarget, true) -- B2: siloer i række: strengt opslag giver hver sin markør check("B2 silo 1 markør", byId.silo1.loadMarker.id, 6) check("B2 silo 2 markør", byId.silo2.loadMarker.id, 7) strictLoadAt[7] = nil ADBuildings.invalidate() check("B2 silo uden strengt match: ingen læssemarkør", ADBuildings.find(adEnv, 1, "silo2").loadMarker, nil) strictLoadAt[7] = silo2Station ADBuildings.invalidate() -- B3: byMarker (omvendt opslag) check("B3 mælkemarkør -> stald (load)", ADBuildings.byMarker(adEnv, 1, 1, "load").id, "barn1") check("B3 fodermarkør -> stald (unload)", ADBuildings.byMarker(adEnv, 1, 2, "unload").id, "barn1") check("B3 fodermarkør er ikke load", ADBuildings.byMarker(adEnv, 1, 2, "load"), nil) check("B3 fjern markør -> nil", ADBuildings.byMarker(adEnv, 1, 10, "load"), nil) -- B4: id-fallback uden uniqueId check("B4 id fra position", ADBuildings.getId({rootNode = {x = 12.6, z = -3.2}}), "pos:13:-3") check("B4 id fra uniqueId", ADBuildings.getId(barn), "barn1") -- B5: cache: samme tabel inden for CACHE_MS, ny efter invalidate local first = ADBuildings.list(adEnv, 1) check("B5 cachet", ADBuildings.list(adEnv, 1) == first, true) ADBuildings.invalidate() check("B5 ny efter invalidate", ADBuildings.list(adEnv, 1) ~= first, true) -- B6: sortering efter NAVN (naturlig talrækkefølge), dernæst første markørnavn — ikke efter slags local order = {} for _, b in ipairs(ADBuildings.list(adEnv, 1)) do table.insert(order, b.name) end check("B6 rækkefølge", table.concat(order, ","), "Kostald 1,Mejeri,Palleskur,Silo 1,Silo 2,Sukkerfabrik") check("B6 naturlig sortering", ADBuildings.naturalLess("Silo 9", "Silo 10"), true) check("B6 naturlig sortering, tal før tekst-lighed", ADBuildings.naturalLess("25 Silo Storage", "26 Silo Storage"), true) check("B6 naturlig sortering ens navn -> markørnavn", ADBuildings.compare({name = "Farma", loadMarkers = {{name = "30 Silo"}}}, {name = "Farma", loadMarkers = {{name = "4 Silo"}}}), false) -- B-DOB: silo der kun kan FYLDES (drive-on-bunker ved biogas: aflæsning, ingen læssestation) = mål, ikke kilde do local dob = placeable("dob1", "DOB 115", 5000, 0, {spec_silo = {}}) table.insert(unloadStations, {owningPlaceable = dob, unloadTriggers = {{exactFillRootNode = {x = 5000, z = 5}}}}) addMarker(21, "Biogas Drop 1", "Biogas", 5000, 12) ADBuildings.invalidate() local byIdDob = {} for _, b in ipairs(ADBuildings.list(adEnv, 1)) do byIdDob[b.id] = b end check("B-DOB kan være mål", byIdDob.dob1.canBeTarget, true) check("B-DOB ikke kilde (intet at hente)", byIdDob.dob1.canBeSource, false) check("B-DOB aflæsningsmarkør", byIdDob.dob1.unloadMarker.id, 21) check("B-DOB almindelig silo stadig ikke mål", byIdDob.silo1.canBeTarget, false) end -- B-SEP: bygning med læssestation men uden silo/fabrik/stald-spec (Pumps&Hoses separatorhal: digestat-udlevering) do local sep = placeable("sep1", "Separator Hall", 7000, 0, {spec_manureSeparator = {}}) table.insert(loadStations, {owningPlaceable = sep, loadTriggers = {{triggerNode = {x = 7000, z = 5}}}}) addMarker(41, "Digestate pickup", "Biogas", 7000, 10) ADBuildings.invalidate() local bySep = {} for _, b in ipairs(ADBuildings.list(adEnv, 1)) do bySep[b.id] = b end check("B-SEP findes som lager", bySep.sep1 and bySep.sep1.kind, "storage") check("B-SEP kan være kilde", bySep.sep1 and bySep.sep1.canBeSource, true) check("B-SEP læssemarkør", bySep.sep1 and bySep.sep1.loadMarker and bySep.sep1.loadMarker.id, 41) end -- B-DROP: fabrik med pickup-markør TÆT på aflæsningstriggeren og en separat drop-markør længere væk -- (Sugarbeet Crusher): aflæsningsmarkøren skal være drop, ikke bygningens egen læssemarkør do local crusher = placeable("crusher1", "Sugarbeet Crusher", 8000, 0, {spec_productionPoint = {productionPoint = {productions = {}, storage = {}}}}) table.insert(loadStations, {owningPlaceable = crusher, loadTriggers = {{triggerNode = {x = 8000, z = 5}}}}) table.insert(unloadStations, {owningPlaceable = crusher, unloadTriggers = {{exactFillRootNode = {x = 8003, z = 2}}}}) addMarker(51, "Sugar Beet Cut Pickup", "Fabrication", 8000, 8) -- 3 m fra læs, ~6 m fra aflæsning addMarker(52, "Sugar Beet Cut Beet Drop", "Fabrication", 8012, 2) -- 9 m fra aflæsning ADBuildings.invalidate() local byC = {} for _, b in ipairs(ADBuildings.list(adEnv, 1)) do byC[b.id] = b end check("B-DROP læssemarkør = pickup", byC.crusher1.loadMarker.id, 51) check("B-DROP aflæsningsmarkør = drop (ikke pickup)", byC.crusher1.unloadMarker.id, 52) -- kun én fælles markør (AIO Load / Unload): bruges til begge local aio = placeable("aio1", "AIO", 9000, 0, {spec_productionPoint = {productionPoint = {productions = {}, storage = {}}}}) table.insert(loadStations, {owningPlaceable = aio, loadTriggers = {{triggerNode = {x = 9000, z = 5}}}}) table.insert(unloadStations, {owningPlaceable = aio, unloadTriggers = {{exactFillRootNode = {x = 9002, z = 5}}}}) addMarker(53, "AIO Load / Unload", "Fabrication", 9000, 9) ADBuildings.invalidate() for _, b in ipairs(ADBuildings.list(adEnv, 1)) do byC[b.id] = b end check("B-DROP fælles markør bruges til aflæsning", byC.aio1.unloadMarker.id, 53) check("B-DROP silo beholder sin egen markør (ikke nabosiloens)", byC.silo1.unloadMarker.id, 6) end print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)