From abbe40da017d705a4a27142caf9f962ba8a69a13 Mon Sep 17 00:00:00 2001 From: masterdraco Date: Sat, 26 Sep 2026 12:38:25 +0200 Subject: [PATCH] =?UTF-8?q?fix(markarbejde):=20afgr=C3=B8de=20og=20v=C3=A6?= =?UTF-8?q?kststadie=20fra=20field.fieldState=20(spillets=20marktilstand);?= =?UTF-8?q?=20getFieldDataAtWorldPosition's=202.=20v=C3=A6rdi=20er=20jord-?= =?UTF-8?q?bits,=20ikke=20v=C3=A6kst=20=E2=80=94=20F108=20majs=20=3D=20bar?= =?UTF-8?q?=20jord;=20h=C3=B8stet=20mark=20vises=20som=20'stub=20(afgr?= =?UTF-8?q?=C3=B8de)'=20(v1.28.7.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adFieldView.lua | 9 ++++++ FS25_ADSmartPickup/adFields.lua | 29 ++++++++++++++----- .../gui/SmartPickupFieldTab.lua | 4 +-- FS25_ADSmartPickup/l10n/l10n_da.xml | 1 + FS25_ADSmartPickup/l10n/l10n_en.xml | 1 + FS25_ADSmartPickup/modDesc.xml | 2 +- tests/test_adFieldView.lua | 7 +++++ tests/test_adFieldsPolygon.lua | 28 +++++++++++++++++- tests/test_adFieldsScan.lua | 6 ++-- 9 files changed, 73 insertions(+), 14 deletions(-) diff --git a/FS25_ADSmartPickup/adFieldView.lua b/FS25_ADSmartPickup/adFieldView.lua index 6addb3c..650ee2a 100644 --- a/FS25_ADSmartPickup/adFieldView.lua +++ b/FS25_ADSmartPickup/adFieldView.lua @@ -37,3 +37,12 @@ function ADFieldView.soilParts(info) if (info.weed or 0) >= ADFieldModel.WEED_MIN then table.insert(parts, "weed") end return parts end + +-- Afgrødekolonnen: høstet mark = "stub (Hvede)", bar mark = "bar jord", ellers afgrøden. +function ADFieldView.cropText(info, getText) + if info.kind == "bare" and info.stubbleOf ~= nil then + return string.format(getText("spu_field_stubble"), tostring(info.stubbleOf)) + end + if info.kind == "bare" then return getText("spu_field_bare") end + return tostring(info.cropTitle or "-") +end diff --git a/FS25_ADSmartPickup/adFields.lua b/FS25_ADSmartPickup/adFields.lua index 96582d4..e64c57d 100644 --- a/FS25_ADSmartPickup/adFields.lua +++ b/FS25_ADSmartPickup/adFields.lua @@ -153,6 +153,15 @@ end ADFields.SAMPLE_DIRECTIONS = 16 +-- field.fieldState (FS25, bekræftet i AI-Bonde via aifProbe): {fruitIndex|nil, growthState} eller nil +-- når spillet ikke har tilstanden (så bruges punkt-afstemningen). +function ADFields.readFieldState(field) + local state = field ~= nil and field.fieldState or nil + if type(state) ~= "table" or type(state.fruitTypeIndex) ~= "number" then return nil end + local fruitIndex = state.fruitTypeIndex > 0 and state.fruitTypeIndex or nil + return {fruitIndex = fruitIndex, growthState = fruitIndex ~= nil and state.growthState or nil} +end + -- Markens omrids som {{x, z}, ...}. FS25: field:getDensityMapPolygon():getVerticesList() (flad liste -- x1, z1, x2, z2 ... — som Courseplay); ældre: polygonPoints (noder). Tom liste hvis intet findes. function ADFields.readPolygon(field) @@ -243,7 +252,7 @@ end local function newScan(adEnv, entry) local field, fieldId = entry.field, entry.id - local scan = {id = fieldId, queue = {}, head = 1, tail = 0, points = {}, fruitVotes = {}, growthVotes = {}, + local scan = {id = fieldId, queue = {}, head = 1, tail = 0, points = {}, fruitVotes = {}, anySum = 0, readySum = 0, soil = {fert = {0, 0}, lime = {0, 0}, plowLevel = {0, 0}, weed = {0, 0}}} local info = {id = fieldId, field = field, points = scan.points, verts = {}, mowable = false, readyRatio = 0} scan.info = info @@ -289,7 +298,15 @@ end -- Når afgrøden kendes: klar-andel, vækststadie og jord pr. punkt (én opgave pr. punkt). function ADFields.scanPerFruit(scan) local info = scan.info - info.fruitIndex = winner(scan.fruitVotes) + -- spillets egen marktilstand (som fields.xml) er sandheden; punkt-afstemningen er reserve. + -- (getFieldDataAtWorldPosition giver isOnField, densityBits, groundType — IKKE vækststadie) + local state = ADFields.readFieldState(info.field) + info.growthState = state ~= nil and state.growthState or nil + if state ~= nil then + info.fruitIndex = state.fruitIndex + else + info.fruitIndex = winner(scan.fruitVotes) + end local fruitIndex = info.fruitIndex local settings = missionSettings() scan.settings = settings @@ -301,11 +318,6 @@ function ADFields.scanPerFruit(scan) if okA and anyPixels then scan.anySum = scan.anySum + anyPixels end local okR, _, readyPixels = pcall(FSDensityMapUtil.getFruitArea, fruitIndex, x - 2, z - 2, x + 2, z, x, z + 2, false, false) if okR and readyPixels then scan.readySum = scan.readySum + readyPixels end - local okG, _, state = pcall(function() - local y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 1, z) - return FSDensityMapUtil.getFieldDataAtWorldPosition(x, y, z) - end) - if okG and type(state) == "number" then vote(scan.growthVotes, state) end end end) push(scan, function() @@ -345,11 +357,12 @@ local function finishScan(adEnv, scan) info.cropTitle = fillType ~= nil and fillType.title or (fruit ~= nil and fruit.name) or "?" end info.kind = ADFields.classify(info.fruitIndex, info.mowable, info.readyRatio) - info.phase = fruit ~= nil and ADFields.growthPhase(winner(scan.growthVotes), fruit) or nil + info.phase = fruit ~= nil and ADFields.growthPhase(info.growthState, fruit) or nil info.growing = info.fruitIndex ~= nil and ADFields.isGrowing(info.phase, info.anyPixels, info.readyRatio) -- høstet stub eller visnet afgrøde er i praksis en bar mark (klargøring/såning) if info.kind == "harvest" and (info.phase == "cut" or info.phase == "withered" or info.phase == "none") then info.kind = "bare" + info.stubbleOf = info.phase == "cut" and info.cropTitle or nil end local settings = scan.settings or missionSettings() for key, sum in pairs(scan.soil) do diff --git a/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua b/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua index 2651aed..d0f5fe2 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFieldTab.lua @@ -109,7 +109,7 @@ function SmartPickupFrame:fieldCells(row) table.insert(names, ADRuns.vehicleLabel(assignment.vehicle)) end local name = string.format("%s%sF%d", info.id == self.selectedFieldId and "> " or "", info.markerId == nil and "! " or "", info.id) - local crop = info.kind == "bare" and self.i18n:getText("spu_field_bare") or (info.cropTitle or "-") + local crop = ADFieldView.cropText(info, function(key) return self.i18n:getText(key) end) return { name, crop, self:fieldPlanText(field, info), self.i18n:getText(field.plan.mode == "auto" and "spu_field_mode_auto" or "spu_field_mode_manual"), @@ -190,7 +190,7 @@ function SmartPickupFrame:fillFieldDetail(adEnv, info) local field = ADFieldJobs.getField(info.id) local plan = field.plan local yesNo = {i18n:getText("ui_no"), i18n:getText("ui_yes")} - local crop = info.kind == "bare" and i18n:getText("spu_field_bare") or tostring(info.cropTitle or "-") + local crop = ADFieldView.cropText(info, function(key) return i18n:getText(key) end) self:addTextRow(string.format(i18n:getText("spu_field_section"), info.id, crop)) local targetTexts, targetValues = self:sowFruitChoices("spu_field_target_none") self:addChoiceRow("fieldTarget", i18n:getText("spu_field_target"), targetTexts, targetValues, plan.targetFruit or "") diff --git a/FS25_ADSmartPickup/l10n/l10n_da.xml b/FS25_ADSmartPickup/l10n/l10n_da.xml index 1067ef8..82f8a75 100644 --- a/FS25_ADSmartPickup/l10n/l10n_da.xml +++ b/FS25_ADSmartPickup/l10n/l10n_da.xml @@ -94,6 +94,7 @@ + diff --git a/FS25_ADSmartPickup/l10n/l10n_en.xml b/FS25_ADSmartPickup/l10n/l10n_en.xml index e916ab2..75c98da 100644 --- a/FS25_ADSmartPickup/l10n/l10n_en.xml +++ b/FS25_ADSmartPickup/l10n/l10n_en.xml @@ -94,6 +94,7 @@ + diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 5194961..4125de9 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.28.6.0 + 1.28.7.0 <en>AD Smart Pickup</en> diff --git a/tests/test_adFieldView.lua b/tests/test_adFieldView.lua index 518bd02..d677f26 100644 --- a/tests/test_adFieldView.lua +++ b/tests/test_adFieldView.lua @@ -38,5 +38,12 @@ local parts = V.soilParts({lime = 0.2, fert = 1, fertMax = 2, weed = 3, needs = check("V5 dele", table.concat(parts, ","), "lime,plow,fert,weed") check("V5 intet", #V.soilParts({lime = 2, fert = 2, fertMax = 2, weed = 0, needs = {}}), 0) +-- cropText: høstet = stub (afgrøde), bar = bar jord, ellers afgrøden +local texts = {spu_field_stubble = "stub (%s)", spu_field_bare = "bar jord"} +local function T(key) return texts[key] end +check("FVcrop stub", ADFieldView.cropText({kind = "bare", stubbleOf = "Hvede", cropTitle = "Hvede"}, T), "stub (Hvede)") +check("FVcrop bar", ADFieldView.cropText({kind = "bare"}, T), "bar jord") +check("FVcrop afgrøde", ADFieldView.cropText({kind = "harvest", cropTitle = "Majs"}, T), "Majs") + print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1) diff --git a/tests/test_adFieldsPolygon.lua b/tests/test_adFieldsPolygon.lua index 41db33f..8e171d5 100644 --- a/tests/test_adFieldsPolygon.lua +++ b/tests/test_adFieldsPolygon.lua @@ -15,7 +15,7 @@ local MAIZE = 10 function getWorldTranslation() return 0, 0, 0 end function getTerrainHeightAtWorldPos() return 0 end -- markskiltet står i marken, men ved en stribe uden afgrøde (x > 1400) -local function cropAt(x) return x <= 1400 and MAIZE or nil end +function cropAt(x) return x <= 1400 and MAIZE or nil end FSDensityMapUtil = { getFieldDataAtWorldPosition = function() return 1, 2 end, getFruitTypeIndexAtWorldPos = function(x, z) return cropAt(x) end, @@ -56,5 +56,31 @@ check("PG3 majsen findes trods skiltet på bar stribe", info and info.fruitName, check("PG4 ikke bar mark", info and info.kind, "harvest") check("PG5 markør ved kanten findes (afstand til omridset)", info and info.markerId, 900) check("PG6 afstand = til kanten", info and info.markerDistance, 5) + +-- PG7-9: field.fieldState er spillets sandhed (fields.xml: MAIZE growthState 2); jord-bits fra +-- getFieldDataAtWorldPosition (2. værdi) er IKKE vækststadie. Høstet mark (cutState) = bar, vist som stub. + +field.fieldState = {fruitTypeIndex = MAIZE, growthState = 2} +FSDensityMapUtil.getFieldDataAtWorldPosition = function() return true, 0 end -- jord-bits 0 lignede "ingen vækst" +local function rescan() + ADFields.cache, ADFields.listCache, ADFields.activeScan, ADFields.lastScanStart = {}, nil, nil, nil + for _ = 1, 2000 do + if ADFields.getInfo(108) ~= nil then break end + ADFields.scanStep(adEnv, 1, now) + now = now + 16 + end + return ADFields.getInfo(108) +end +info = rescan() +check("PG7 majs i vækst (fieldState), ikke bar", info and info.kind, "harvest") +check("PG7 fase vokser", info and info.phase, "growing") +field.fieldState = {fruitTypeIndex = MAIZE, growthState = 9} +info = rescan() +check("PG8 høstet (cutState) = bar", info and info.kind, "bare") +check("PG8 stub af majs", info and info.stubbleOf, "Majs") +field.fieldState = {fruitTypeIndex = 0, growthState = 0} +cropAt = function() return nil end +info = rescan() +check("PG9 ingen afgrøde = bar uden stub", info and info.kind .. "/" .. tostring(info.stubbleOf), "bare/nil") print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1) diff --git a/tests/test_adFieldsScan.lua b/tests/test_adFieldsScan.lua index febcd97..796f3b5 100644 --- a/tests/test_adFieldsScan.lua +++ b/tests/test_adFieldsScan.lua @@ -17,7 +17,7 @@ function getWorldTranslation(node) local p = nodes[node]; return p[1], 0, p[2] e function getTerrainHeightAtWorldPos() return 0 end local calls = 0 FSDensityMapUtil = { - getFieldDataAtWorldPosition = function() calls = calls + 1; return 1, 6 end, -- på mark, vækststadie 6 + getFieldDataAtWorldPosition = function() calls = calls + 1; return true, 170 end, -- på mark (2. værdi = jord-bits, IKKE vækst) getFruitTypeIndexAtWorldPos = function() calls = calls + 1; return WHEAT end, getFruitArea = function(_, _, _, _, _, _, _, any) calls = calls + 1; return 0, any and 10 or 10 end, } @@ -30,7 +30,9 @@ g_fruitTypeManager = { } g_fillTypeManager = {getConverterDataByName = function() return {} end, getFillTypeNameByIndex = function() return "X" end} g_farmlandManager = {getFarmlandOwner = function() return 1 end} -local field = {getId = function() return 7 end, farmland = {id = 70}, polygonPoints = {101, 102, 103, 104}, posX = 50, posZ = 50} +-- spillets egen marktilstand (field.fieldState, som fields.xml): afgrøde + vækststadie +local field = {getId = function() return 7 end, farmland = {id = 70}, polygonPoints = {101, 102, 103, 104}, posX = 50, posZ = 50, + fieldState = {fruitTypeIndex = WHEAT, growthState = 6}} g_fieldManager = {getFields = function() return {field} end} g_currentMission = {terrainRootNode = 1, missionInfo = {}, fieldGroundSystem = { getDensityMapData = function() return 1, 0, 2 end, getMaxValue = function() return 2 end}}