feat(marker): vender/river/læssevogn genbruger slåmaskinens Courseplay-kursus (v1.22.0.0)
In-game 25/9: læssevognens nye CP-kursus lå forskudt i forhold til skårene -> ikke samlet korrekt. Slåkurset gemmes pr. mark (kopi) og kopieres til næste trin med vehicle:cpCopyCourse; efter genindlæsning hentes det fra slåmaskinen (mowVehicle gemt i ADSmartPickup_fields.xml).
This commit is contained in:
@@ -74,7 +74,16 @@ function ADCpBridge.isWorking(vehicle)
|
|||||||
return vehicle.getIsAIActive ~= nil and vehicle:getIsAIActive() or false
|
return vehicle.getIsAIActive ~= nil and vehicle:getIsAIActive() or false
|
||||||
end
|
end
|
||||||
|
|
||||||
function ADCpBridge.start(vehicle, fieldX, fieldZ, onDone)
|
-- Køretøjets nuværende Courseplay-kursus (slåmaskinens kursus genbruges af de næste trin).
|
||||||
|
function ADCpBridge.getCourse(vehicle)
|
||||||
|
if vehicle == nil or vehicle.getFieldWorkCourse == nil then return nil end
|
||||||
|
local ok, course = pcall(vehicle.getFieldWorkCourse, vehicle)
|
||||||
|
return ok and course or nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- course (valgfri): et færdigt kursus (slåmaskinens) der kopieres til køretøjet i stedet for at lave et
|
||||||
|
-- nyt — så vender/river/læssevogn kører præcis slåmaskinens baner (in-game 25/9: nyt kursus lå forskudt).
|
||||||
|
function ADCpBridge.start(vehicle, fieldX, fieldZ, onDone, course)
|
||||||
if not ADCpBridge.isAvailable() then
|
if not ADCpBridge.isAvailable() then
|
||||||
return nil, "Courseplay (FIELDWORK_CP) findes ikke"
|
return nil, "Courseplay (FIELDWORK_CP) findes ikke"
|
||||||
end
|
end
|
||||||
@@ -93,16 +102,27 @@ function ADCpBridge.start(vehicle, fieldX, fieldZ, onDone)
|
|||||||
handle.finished = true
|
handle.finished = true
|
||||||
if not handle.cancelled then onDone(ok, reason) end
|
if not handle.cancelled then onDone(ok, reason) end
|
||||||
end
|
end
|
||||||
local function generateAndStart()
|
local function startWithCourse()
|
||||||
if handle.cancelled then return end
|
|
||||||
job:onClickGenerateFieldWorkCourse(function(course)
|
|
||||||
if handle.cancelled then return end
|
|
||||||
if not course then return finish(false, "Courseplay kunne ikke lave kursus") end
|
|
||||||
job:setValues()
|
job:setValues()
|
||||||
local ok, err = job:validate(farmId)
|
local ok, err = job:validate(farmId)
|
||||||
if not ok then return finish(false, "Courseplay: " .. tostring(err)) end
|
if not ok then return finish(false, "Courseplay: " .. tostring(err)) end
|
||||||
g_currentMission.aiSystem:startJob(job, farmId)
|
g_currentMission.aiSystem:startJob(job, farmId)
|
||||||
finish(true)
|
finish(true, handle.copiedCourse and "copied" or nil)
|
||||||
|
end
|
||||||
|
local function generateAndStart()
|
||||||
|
if handle.cancelled then return end
|
||||||
|
if course ~= nil and vehicle.cpCopyCourse ~= nil then
|
||||||
|
local copied, copyError = pcall(vehicle.cpCopyCourse, vehicle, course)
|
||||||
|
if copied then
|
||||||
|
handle.copiedCourse = true
|
||||||
|
return startWithCourse()
|
||||||
|
end
|
||||||
|
Logging.warning("ADSmartPickup: kunne ikke kopiere slåkursus: %s — laver nyt", tostring(copyError))
|
||||||
|
end
|
||||||
|
job:onClickGenerateFieldWorkCourse(function(generated)
|
||||||
|
if handle.cancelled then return end
|
||||||
|
if not generated then return finish(false, "Courseplay kunne ikke lave kursus") end
|
||||||
|
startWithCourse()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
handle.onBoundary = function(_, success, message)
|
handle.onBoundary = function(_, success, message)
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ ADFieldJobs.PLAYER_DRIVING_KMH = 3
|
|||||||
-- Courseplay kan efterlade hjørner på skæve marker: efter så mange færdige slå-ture går marken videre.
|
-- Courseplay kan efterlade hjørner på skæve marker: efter så mange færdige slå-ture går marken videre.
|
||||||
ADFieldJobs.MAX_MOW_PASSES = 2
|
ADFieldJobs.MAX_MOW_PASSES = 2
|
||||||
ADFieldJobs.state = {fields = {}, fleet = {}, assignments = {}}
|
ADFieldJobs.state = {fields = {}, fleet = {}, assignments = {}}
|
||||||
|
-- mark-id -> kopi af slåmaskinens Courseplay-kursus (kun i hukommelsen; efter genindlæsning hentes det
|
||||||
|
-- igen fra slåmaskinen, som CP selv gemmer kurset på)
|
||||||
|
ADFieldJobs.courses = {}
|
||||||
ADFieldJobs.timer = 0
|
ADFieldJobs.timer = 0
|
||||||
ADFieldJobs.now = 0
|
ADFieldJobs.now = 0
|
||||||
ADFieldJobs.loaded = false
|
ADFieldJobs.loaded = false
|
||||||
@@ -255,6 +258,18 @@ local function dispatch(adEnv, field, info, role)
|
|||||||
note(field.id, {reason = false})
|
note(field.id, {reason = false})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Slåkurset for marken: gemt kopi, ellers slåmaskinens nuværende kursus (efter genindlæsning).
|
||||||
|
local function mowCourse(adEnv, field)
|
||||||
|
if ADFieldJobs.courses[field.id] ~= nil then return ADFieldJobs.courses[field.id] end
|
||||||
|
if field.mowVehicleId == nil then return nil end
|
||||||
|
for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do
|
||||||
|
if ADRunsController.getVehicleId(vehicle) == field.mowVehicleId then
|
||||||
|
return ADCpBridge.getCourse(vehicle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
local function beginWork(adEnv, field, info, assignment)
|
local function beginWork(adEnv, field, info, assignment)
|
||||||
local vehicle = assignment.vehicle
|
local vehicle = assignment.vehicle
|
||||||
if assignment.role == "collector" then
|
if assignment.role == "collector" then
|
||||||
@@ -283,20 +298,27 @@ local function beginWork(adEnv, field, info, assignment)
|
|||||||
local point = info.points[1] or {x = info.x, z = info.z}
|
local point = info.points[1] or {x = info.x, z = info.z}
|
||||||
assignment.phase = "starting"
|
assignment.phase = "starting"
|
||||||
assignment.since = ADFieldJobs.now
|
assignment.since = ADFieldJobs.now
|
||||||
|
local course = assignment.role ~= "mower" and mowCourse(adEnv, field) or nil
|
||||||
|
if assignment.role ~= "mower" and course == nil then
|
||||||
|
log(field.id, "intet slåkursus kendt — Courseplay laver et nyt kursus til %s", assignment.role)
|
||||||
|
end
|
||||||
local handle, err = ADCpBridge.start(vehicle, point.x, point.z, function(ok, reason)
|
local handle, err = ADCpBridge.start(vehicle, point.x, point.z, function(ok, reason)
|
||||||
if ok then
|
if ok then
|
||||||
assignment.phase = "working"
|
assignment.phase = "working"
|
||||||
assignment.since = ADFieldJobs.now
|
assignment.since = ADFieldJobs.now
|
||||||
if assignment.role == "mower" then
|
if assignment.role == "mower" then
|
||||||
note(field.id, {mowWidth = assignment.width})
|
note(field.id, {mowWidth = assignment.width, mowVehicleId = assignment.vehicleId})
|
||||||
|
local mowed = ADCpBridge.getCourse(vehicle)
|
||||||
|
local copied = mowed ~= nil and mowed.copy ~= nil and select(2, pcall(mowed.copy, mowed)) or mowed
|
||||||
|
ADFieldJobs.courses[field.id] = type(copied) == "table" and copied or mowed
|
||||||
end
|
end
|
||||||
log(field.id, "Courseplay startet (%s)", assignment.role)
|
log(field.id, "Courseplay startet (%s%s)", assignment.role, reason == "copied" and ", slåkursus kopieret" or "")
|
||||||
else
|
else
|
||||||
release(assignment)
|
release(assignment)
|
||||||
note(field.id, {retryAt = ADFieldJobs.now + ADFieldModel.RETRY_MS, reason = {text = tostring(reason)}})
|
note(field.id, {retryAt = ADFieldJobs.now + ADFieldModel.RETRY_MS, reason = {text = tostring(reason)}})
|
||||||
log(field.id, "Courseplay fejlede: %s", tostring(reason))
|
log(field.id, "Courseplay fejlede: %s", tostring(reason))
|
||||||
end
|
end
|
||||||
end)
|
end, course)
|
||||||
if handle == nil then
|
if handle == nil then
|
||||||
release(assignment)
|
release(assignment)
|
||||||
log(field.id, "Courseplay kunne ikke startes: %s", tostring(err))
|
log(field.id, "Courseplay kunne ikke startes: %s", tostring(err))
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ function ADFieldModel.start(field)
|
|||||||
copy.retryAt = 0
|
copy.retryAt = 0
|
||||||
copy.reason = nil
|
copy.reason = nil
|
||||||
copy.mowWidth = nil
|
copy.mowWidth = nil
|
||||||
|
copy.mowVehicleId = nil
|
||||||
return copy
|
return copy
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -156,6 +157,7 @@ function ADFieldModel.toRecord(field)
|
|||||||
id = field.id, stage = field.stage, mode = field.plan.mode, product = field.plan.product,
|
id = field.id, stage = field.stage, mode = field.plan.mode, product = field.plan.product,
|
||||||
rake = field.plan.rake and 1 or 0, store = table.concat(field.plan.storeBuildingIds, " "),
|
rake = field.plan.rake and 1 or 0, store = table.concat(field.plan.storeBuildingIds, " "),
|
||||||
mowWidth = field.mowWidth or 0,
|
mowWidth = field.mowWidth or 0,
|
||||||
|
mowVehicle = field.mowVehicleId or "",
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -167,5 +169,6 @@ function ADFieldModel.fromRecord(record)
|
|||||||
field.plan.rake = record.rake == 1 or record.rake == true
|
field.plan.rake = record.rake == 1 or record.rake == true
|
||||||
for id in string.gmatch(record.store or "", "%S+") do table.insert(field.plan.storeBuildingIds, id) end
|
for id in string.gmatch(record.store or "", "%S+") do table.insert(field.plan.storeBuildingIds, id) end
|
||||||
field.mowWidth = (record.mowWidth or 0) > 0 and record.mowWidth or nil
|
field.mowWidth = (record.mowWidth or 0) > 0 and record.mowWidth or nil
|
||||||
|
field.mowVehicleId = record.mowVehicle ~= nil and record.mowVehicle ~= "" and record.mowVehicle or nil
|
||||||
return field
|
return field
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ function ADFieldStorage.save(state)
|
|||||||
xmlFile:setInt(key .. "#rake", record.rake)
|
xmlFile:setInt(key .. "#rake", record.rake)
|
||||||
xmlFile:setString(key .. "#store", record.store)
|
xmlFile:setString(key .. "#store", record.store)
|
||||||
xmlFile:setFloat(key .. "#mowWidth", record.mowWidth)
|
xmlFile:setFloat(key .. "#mowWidth", record.mowWidth)
|
||||||
|
xmlFile:setString(key .. "#mowVehicle", record.mowVehicle)
|
||||||
index = index + 1
|
index = index + 1
|
||||||
end
|
end
|
||||||
local vehicleIndex = 0
|
local vehicleIndex = 0
|
||||||
@@ -51,7 +52,7 @@ function ADFieldStorage.load()
|
|||||||
id = xmlFile:getInt(key .. "#id"), stage = xmlFile:getString(key .. "#stage"),
|
id = xmlFile:getInt(key .. "#id"), stage = xmlFile:getString(key .. "#stage"),
|
||||||
mode = xmlFile:getString(key .. "#mode"), product = xmlFile:getString(key .. "#product"),
|
mode = xmlFile:getString(key .. "#mode"), product = xmlFile:getString(key .. "#product"),
|
||||||
rake = xmlFile:getInt(key .. "#rake"), store = xmlFile:getString(key .. "#store"),
|
rake = xmlFile:getInt(key .. "#rake"), store = xmlFile:getString(key .. "#store"),
|
||||||
mowWidth = xmlFile:getFloat(key .. "#mowWidth"),
|
mowWidth = xmlFile:getFloat(key .. "#mowWidth"), mowVehicle = xmlFile:getString(key .. "#mowVehicle"),
|
||||||
})
|
})
|
||||||
if field.id ~= nil then result.fields[field.id] = field end
|
if field.id ~= nil then result.fields[field.id] = field end
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
<modDesc descVersion="107">
|
<modDesc descVersion="107">
|
||||||
<author>masterdraco</author>
|
<author>masterdraco</author>
|
||||||
<version>1.21.6.0</version>
|
<version>1.22.0.0</version>
|
||||||
<title>
|
<title>
|
||||||
<en>AD Smart Pickup</en>
|
<en>AD Smart Pickup</en>
|
||||||
</title>
|
</title>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# AD Smart Pickup — brugermanual
|
# AD Smart Pickup — brugermanual
|
||||||
|
|
||||||
Version 1.21.6 · Farming Simulator 25 · tillæg til AutoDrive
|
Version 1.22.0 · Farming Simulator 25 · tillæg til AutoDrive
|
||||||
|
|
||||||
*English version: [USER_MANUAL.md](USER_MANUAL.md)*
|
*English version: [USER_MANUAL.md](USER_MANUAL.md)*
|
||||||
|
|
||||||
@@ -551,8 +551,9 @@ hvilket trin og hvilken maskine. Kræver **Courseplay** ud over AutoDrive.
|
|||||||
|
|
||||||
- Courseplay kan højst køre **50 m** bredt. Et sæt over 50 m sendes ikke ud (`!! over 50 m` i
|
- Courseplay kan højst køre **50 m** bredt. Et sæt over 50 m sendes ikke ud (`!! over 50 m` i
|
||||||
markflåden).
|
markflåden).
|
||||||
- Moden husker, hvor bredt marken blev **slået**. Vender, river og læssevogn skal være **mindst lige
|
- Moden husker, hvor bredt marken blev **slået**, og **slåmaskinens Courseplay-kursus**. Vender, river og
|
||||||
så brede**, så hver bane dækker det, slåmaskinen lagde. Med Unrealistic Pack: sæt slåmaskinen og
|
læssevogn kører præcis samme kursus (kopieret), så de rammer skårene. De skal være **mindst lige så
|
||||||
|
brede** som slåmaskinen. Med Unrealistic Pack: sæt slåmaskinen og
|
||||||
læssevognene til samme bredde, fx 40,8 m.
|
læssevognene til samme bredde, fx 40,8 m.
|
||||||
|
|
||||||
### En mark
|
### En mark
|
||||||
|
|||||||
+4
-3
@@ -1,6 +1,6 @@
|
|||||||
# AD Smart Pickup — user manual
|
# AD Smart Pickup — user manual
|
||||||
|
|
||||||
Version 1.21.6 · Farming Simulator 25 · add-on for AutoDrive
|
Version 1.22.0 · Farming Simulator 25 · add-on for AutoDrive
|
||||||
|
|
||||||
*Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)*
|
*Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)*
|
||||||
|
|
||||||
@@ -557,8 +557,9 @@ which step and which machine. Requires **Courseplay** in addition to AutoDrive.
|
|||||||
|
|
||||||
- Courseplay can work at most **50 m** wide. A rig over 50 m is not sent out (`!! over 50 m` in the
|
- Courseplay can work at most **50 m** wide. A rig over 50 m is not sent out (`!! over 50 m` in the
|
||||||
fleet).
|
fleet).
|
||||||
- The mod remembers how wide the field was **mowed**. Tedder, rake and loading wagon must be **at least
|
- The mod remembers how wide the field was **mowed**, and the **mower's Courseplay course**. Tedder,
|
||||||
as wide**, so every lane covers what the mower laid down. With Unrealistic Pack: set the mower and the
|
rake and loading wagon drive exactly that course (copied), so they hit the swaths. They must be **at
|
||||||
|
least as wide** as the mower. With Unrealistic Pack: set the mower and the
|
||||||
loading wagons to the same width, such as 40.8 m.
|
loading wagons to the same width, such as 40.8 m.
|
||||||
|
|
||||||
### A field
|
### A field
|
||||||
|
|||||||
@@ -38,8 +38,12 @@ Ikke med i etape 1: mejetærskerafgrøder (etape 2), roer (etape 3), jordbehandl
|
|||||||
læssevognene i Unrealistic Pack kan køre 40 m bredt og samler spredt hø op.
|
læssevognene i Unrealistic Pack kan køre 40 m bredt og samler spredt hø op.
|
||||||
6. **Bredde.** Maskiner kører med deres *aktuelle* bredde (Unrealistic Packs `variableWorkWidth`,
|
6. **Bredde.** Maskiner kører med deres *aktuelle* bredde (Unrealistic Packs `variableWorkWidth`,
|
||||||
`aiKeepCurrentWidth`). Courseplay kan højst 50 m → et sæt over 50 m sendes ikke ud (advarsel).
|
`aiKeepCurrentWidth`). Courseplay kan højst 50 m → et sæt over 50 m sendes ikke ud (advarsel).
|
||||||
Marken husker **slåbredden**; opsamling/vending/rivning kræver bredde ≥ slåbredden, så hver bane
|
Marken husker **slåbredden**; opsamling/vending/rivning kræver bredde ≥ slåbredden.
|
||||||
dækker det, slåmaskinen lagde. Så behøver banerne ikke flugte med skårene.
|
**Revideret efter in-game test 25/9:** et nyt Courseplay-kursus til læssevognen lå forskudt i forhold til
|
||||||
|
skårene (anden start/retning/forager). Derfor genbruger vender, river og læssevogn **slåmaskinens
|
||||||
|
kursus** (`vehicle:cpCopyCourse`). Kurset gemmes pr. mark; efter genindlæsning hentes det fra
|
||||||
|
slåmaskinen (id gemt som `mowVehicle`), som Courseplay selv gemmer kurset på. Uden kendt slåkursus
|
||||||
|
laves et nyt som reserve (logges).
|
||||||
7. **Silovalg** genbruger Smart Pickups motor (`ADLoadSwap`): nærmeste silo med plads, der tager varen,
|
7. **Silovalg** genbruger Smart Pickups motor (`ADLoadSwap`): nærmeste silo med plads, der tager varen,
|
||||||
med vej fra `F`-markøren. *Tving lager* pr. mark (som "Lager til" i flows). Fabrikker er ikke mål.
|
med vej fra `F`-markøren. *Tving lager* pr. mark (som "Lager til" i flows). Fabrikker er ikke mål.
|
||||||
8. **Marksilo.** En silo, hvis afstand til markens polygon er ≤ 150 m, er et mellemlager. Den må gerne
|
8. **Marksilo.** En silo, hvis afstand til markens polygon er ≤ 150 m, er et mellemlager. Den må gerne
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ check("M5 Start nu", M.shouldStart(requested), true)
|
|||||||
local started = M.start(ready)
|
local started = M.start(ready)
|
||||||
check("M5 start -> slås", started.stage, "mowing")
|
check("M5 start -> slås", started.stage, "mowing")
|
||||||
check("M5 start rydder forespørgsel", started.startRequested, false)
|
check("M5 start rydder forespørgsel", started.startRequested, false)
|
||||||
|
local oldMow = M.with(ready, {mowVehicleId = "old"})
|
||||||
|
check("M5 start glemmer gammel slåmaskine", M.start(oldMow).mowVehicleId, nil)
|
||||||
|
|
||||||
-- M6: videre gennem trinene; færdig mark bliver klar igen når den er vokset
|
-- M6: videre gennem trinene; færdig mark bliver klar igen når den er vokset
|
||||||
local hay = M.start(M.onReadiness(M.newField(7), 1)); hay.plan.product = "hay"
|
local hay = M.start(M.onReadiness(M.newField(7), 1)); hay.plan.product = "hay"
|
||||||
@@ -76,7 +78,7 @@ check("M7 wantsRig efter pause", M.wantsRig(paused, 0, 1000), "mower")
|
|||||||
check("M7 wantsRig klar = nil", M.wantsRig(ready, 0, 0), nil)
|
check("M7 wantsRig klar = nil", M.wantsRig(ready, 0, 0), nil)
|
||||||
|
|
||||||
-- M8: gem/indlæs bevarer trin, plan og slåbredde
|
-- M8: gem/indlæs bevarer trin, plan og slåbredde
|
||||||
local saved = M.advance(M.start(M.onReadiness(M.newField(109), 1))); saved.mowWidth = 40.8
|
local saved = M.advance(M.start(M.onReadiness(M.newField(109), 1))); saved.mowWidth = 40.8; saved.mowVehicleId = "vehicleBigM"
|
||||||
saved.plan = {mode = "auto", product = "hay", rake = true, storeBuildingIds = {"b12", "b7"}}
|
saved.plan = {mode = "auto", product = "hay", rake = true, storeBuildingIds = {"b12", "b7"}}
|
||||||
local back = M.fromRecord(M.toRecord(saved))
|
local back = M.fromRecord(M.toRecord(saved))
|
||||||
check("M8 id", back.id, 109)
|
check("M8 id", back.id, 109)
|
||||||
@@ -86,6 +88,8 @@ check("M8 product", back.plan.product, "hay")
|
|||||||
check("M8 rake", back.plan.rake, true)
|
check("M8 rake", back.plan.rake, true)
|
||||||
check("M8 lager", table.concat(back.plan.storeBuildingIds, " "), "b12 b7")
|
check("M8 lager", table.concat(back.plan.storeBuildingIds, " "), "b12 b7")
|
||||||
check("M8 slåbredde", back.mowWidth, 40.8)
|
check("M8 slåbredde", back.mowWidth, 40.8)
|
||||||
|
check("M8 slåmaskine", back.mowVehicleId, "vehicleBigM")
|
||||||
|
check("M8 ingen slåmaskine", M.fromRecord({id = 4, stage = "idle"}).mowVehicleId, nil)
|
||||||
check("M8 ukendt trin -> venter", M.fromRecord({id = 3, stage = "bogus"}).stage, "idle")
|
check("M8 ukendt trin -> venter", M.fromRecord({id = 3, stage = "bogus"}).stage, "idle")
|
||||||
|
|
||||||
-- M9: with() kopierer og fletter planen
|
-- M9: with() kopierer og fletter planen
|
||||||
|
|||||||
Reference in New Issue
Block a user