perf+fix: rutetjek gemmes 30 s (hak hvert 5. s); kilde der gav lidt hviler 3 min (æg-vognen til samme hønsehus 3x) (v1.27.3.0)
In-game 26/9: hak ca. hvert 5. s efter 1.27.2 = holdende vognes genplanlægning (ADOutbound/ADLoadSwap hvert 5 s) med AD-stifinding + reserve-BFS gennem 13.550 waypoints pr. kandidat. Rutesvar caches pr. mål og 10 m- område i 30 s (max 2000 poster); langsomme rutetjek logges. Æg: 'ingen mere last' markerer nu kilden som hvilende 3 min, så runden roterer mellem hønsehusene.
This commit is contained in:
@@ -25,6 +25,9 @@ ADOutbound.NOTIFICATION_MS = 8000
|
||||
-- spawnet, forkert farm, ...): kilden udelukkes for varen i EMPTY_SOURCE_TTL_MS og turen afsluttes.
|
||||
ADOutbound.EMPTY_SOURCE_MS = 30000
|
||||
ADOutbound.EMPTY_SOURCE_TTL_MS = 300000
|
||||
-- kilde der gav lidt og så intet mere (fx paller uden for Universal Autoloads rækkevidde): hviler så længe,
|
||||
-- så de andre kilder kommer til (in-game 26/9: æg-vognen kørte til samme hønsehus tre gange i træk)
|
||||
ADOutbound.THIN_SOURCE_REST_MS = 180000
|
||||
-- Autoload-bil på vej til aflæsning: stropperne løsnes så mange meter FØR markøren. Markøren står
|
||||
-- hvor næsen stopper, og en lastbils lad har passeret salgstriggeren dér; AutoDrive løsner selv
|
||||
-- først ved markøren ("AL unload = center"), hvilket er for sent for en lastbil.
|
||||
@@ -42,6 +45,11 @@ local warned = setmetatable({}, {__mode = "k"})
|
||||
local emptyUntil = {}
|
||||
local isInstalled = false
|
||||
|
||||
-- Glem alle "tom/hvilende kilde"-markeringer (tests; og når runs genindlæses).
|
||||
function ADOutbound.resetEmptySources()
|
||||
emptyUntil = {}
|
||||
end
|
||||
|
||||
local function now()
|
||||
if g_currentMission ~= nil and type(g_currentMission.time) == "number" then
|
||||
return g_currentMission.time
|
||||
@@ -753,7 +761,12 @@ function ADOutbound.beforeLoadUpdate(adEnv, task, dt)
|
||||
return true
|
||||
end
|
||||
if state.noProgressMs > ADOutbound.NO_PROGRESS_MS and level > 0 and not spawnPending then
|
||||
Logging.info(ADOutbound.LOG_PREFIX .. "'%s': ingen mere last ved %s; kører med %.0f l", tostring(ADRuns.vehicleLabel(vehicle)), tostring(source ~= nil and source.name or state.current), level)
|
||||
local rests = now() + ADOutbound.THIN_SOURCE_REST_MS
|
||||
for _, fillType in ipairs(state.trip.fillTypes) do
|
||||
local key = tostring(state.current) .. ":" .. tostring(fillType)
|
||||
if emptyUntil[key] == nil or emptyUntil[key] < rests then emptyUntil[key] = rests end
|
||||
end
|
||||
Logging.info(ADOutbound.LOG_PREFIX .. "'%s': ingen mere last ved %s; kører med %.0f l (kilden hviler %d min, så de andre kommer til)", tostring(ADRuns.vehicleLabel(vehicle)), tostring(source ~= nil and source.name or state.current), level, math.floor(ADOutbound.THIN_SOURCE_REST_MS / 60000))
|
||||
state.noProgressMs, state.completed = 0, true
|
||||
task:finished()
|
||||
return true
|
||||
|
||||
@@ -124,11 +124,42 @@ local function graphReaches(adEnv, vehicle, targetId)
|
||||
return false
|
||||
end
|
||||
|
||||
function ADWaitPool.hasRouteTo(adEnv, vehicle, wayPointId)
|
||||
local graph = adEnv.ADGraphManager
|
||||
if graph.getPathTo == nil then
|
||||
return true
|
||||
-- Rutesvar gemmes ROUTE_CACHE_MS pr. mål og 10 m-område: holdende vogne spørger hvert 5. s for hver
|
||||
-- kandidat, og AD's stifinding (+ reserve-søgningen) gennem hele vejnettet gav et hak hvert 5. s
|
||||
-- (in-game 26/9). Vejnettet ændrer sig ikke så hurtigt.
|
||||
ADWaitPool.ROUTE_CACHE_MS = 30000
|
||||
ADWaitPool.ROUTE_CELL_M = 10
|
||||
ADWaitPool.SLOW_ROUTE_MS = 3
|
||||
local routeCache = {}
|
||||
local routeCacheSize = 0
|
||||
ADWaitPool.ROUTE_CACHE_MAX = 2000
|
||||
|
||||
local function remember(key, result, at)
|
||||
if routeCache[key] == nil then
|
||||
routeCacheSize = routeCacheSize + 1
|
||||
if routeCacheSize > ADWaitPool.ROUTE_CACHE_MAX then
|
||||
routeCache, routeCacheSize = {}, 1
|
||||
end
|
||||
end
|
||||
routeCache[key] = {result = result, at = at}
|
||||
end
|
||||
|
||||
local function clockMs()
|
||||
local ok, ms = pcall(function() return netGetTime() end)
|
||||
if ok and type(ms) == "number" then return ms end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function routeKey(vehicle, wayPointId)
|
||||
if vehicle.rootNode == nil or getWorldTranslation == nil then return nil end
|
||||
local ok, x, _, z = pcall(getWorldTranslation, vehicle.rootNode)
|
||||
if not ok or x == nil then return nil end
|
||||
local cell = ADWaitPool.ROUTE_CELL_M
|
||||
return string.format("%s:%d:%d", tostring(wayPointId), math.floor(x / cell), math.floor(z / cell))
|
||||
end
|
||||
|
||||
local function computeRoute(adEnv, vehicle, wayPointId)
|
||||
local graph = adEnv.ADGraphManager
|
||||
if pathReaches(graph:getPathTo(vehicle, wayPointId), wayPointId) then
|
||||
return true
|
||||
end
|
||||
@@ -142,13 +173,45 @@ function ADWaitPool.hasRouteTo(adEnv, vehicle, wayPointId)
|
||||
return false
|
||||
end
|
||||
|
||||
function ADWaitPool.hasRouteTo(adEnv, vehicle, wayPointId)
|
||||
local graph = adEnv.ADGraphManager
|
||||
if graph.getPathTo == nil then
|
||||
return true
|
||||
end
|
||||
local now = clockMs()
|
||||
local key = now ~= nil and routeKey(vehicle, wayPointId) or nil
|
||||
local cached = key ~= nil and routeCache[key] or nil
|
||||
if cached ~= nil and now - cached.at < ADWaitPool.ROUTE_CACHE_MS then
|
||||
return cached.result
|
||||
end
|
||||
local result = computeRoute(adEnv, vehicle, wayPointId)
|
||||
if key ~= nil then
|
||||
local spent = (clockMs() or now) - now
|
||||
remember(key, result, now)
|
||||
if spent > ADWaitPool.SLOW_ROUTE_MS and Logging ~= nil and Logging.info ~= nil
|
||||
and (ADWaitPool.lastSlowLog == nil or now - ADWaitPool.lastSlowLog > 60000) then
|
||||
ADWaitPool.lastSlowLog = now
|
||||
Logging.info("ADSmartPickup: rutetjek til markør %s tog %.1f ms (%s) — gemmes nu i %d s", tostring(wayPointId), spent, result and "vej" or "ingen vej", ADWaitPool.ROUTE_CACHE_MS / 1000)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function ADWaitPool.hasRouteBothWays(adEnv, vehicle, toWayPointId, homeWayPointId)
|
||||
local graph = adEnv.ADGraphManager
|
||||
if graph.getPathTo == nil or graph.pathFromTo == nil then
|
||||
return true
|
||||
end
|
||||
return pathReaches(graph:getPathTo(vehicle, toWayPointId), toWayPointId)
|
||||
local now = clockMs()
|
||||
local key = now ~= nil and routeKey(vehicle, tostring(toWayPointId) .. ">" .. tostring(homeWayPointId)) or nil
|
||||
local cached = key ~= nil and routeCache[key] or nil
|
||||
if cached ~= nil and now - cached.at < ADWaitPool.ROUTE_CACHE_MS then
|
||||
return cached.result
|
||||
end
|
||||
local result = pathReaches(graph:getPathTo(vehicle, toWayPointId), toWayPointId)
|
||||
and pathReaches(graph:pathFromTo(toWayPointId, homeWayPointId), homeWayPointId)
|
||||
if key ~= nil then remember(key, result, now) end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Står AD midt i en (blokeret) af-/pålæsning, stoppes den pænt først — ellers kører
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<modDesc descVersion="107">
|
||||
<author>masterdraco</author>
|
||||
<version>1.27.2.0</version>
|
||||
<version>1.27.3.0</version>
|
||||
<title>
|
||||
<en>AD Smart Pickup</en>
|
||||
</title>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AD Smart Pickup — brugermanual
|
||||
|
||||
Version 1.27.2 · Farming Simulator 25 · tillæg til AutoDrive
|
||||
Version 1.27.3 · Farming Simulator 25 · tillæg til AutoDrive
|
||||
|
||||
*English version: [USER_MANUAL.md](USER_MANUAL.md)*
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Testplan — Markarbejde (fanen Marker), version 1.27.2.0
|
||||
# Testplan — Markarbejde (fanen Marker), version 1.27.3.0
|
||||
|
||||
Stor test-session. Kør testene i rækkefølge: de første bygger opsætningen, de senere bygger på den.
|
||||
Hver test har **Gør**, **Forvent** og **Log** (linjer i `log.txt`, der beviser at det virkede). Loglinjer
|
||||
@@ -11,7 +11,7 @@ samme rækkefølge.
|
||||
|
||||
## 0. Forberedelse
|
||||
|
||||
- [ ] **0.1 Version.** Log: `Available mod: … (Version: 1.27.2.0) FS25_ADSmartPickup`.
|
||||
- [ ] **0.1 Version.** Log: `Available mod: … (Version: 1.27.3.0) FS25_ADSmartPickup`.
|
||||
- [ ] **0.2 Fanen Marker åbner.** ESC → Smart Pickup → fanen **Marker**. Forvent: "Marker indlæses …"
|
||||
i få sekunder, derefter én række pr. ejet mark (også korn-, roe- og bare marker, ikke kun græs).
|
||||
Afgrøde-kolonnen viser afgrøden eller "bar jord".
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# AD Smart Pickup — user manual
|
||||
|
||||
Version 1.27.2 · Farming Simulator 25 · add-on for AutoDrive
|
||||
Version 1.27.3 · Farming Simulator 25 · add-on for AutoDrive
|
||||
|
||||
*Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)*
|
||||
|
||||
|
||||
@@ -345,6 +345,26 @@ check("O13 WARN", lastLog("intet at læsse") ~= nil, true)
|
||||
local choice13b = ADOutbound.choosePickup(adEnv, v13)
|
||||
check("O13 næste plan udelukker den tomme kilde", choice13b.markerIndex, mSugar.markerIndex)
|
||||
|
||||
-- O16: kilden gav LIDT og så intet mere ("ingen mere last") -> kilden hviler, næste tur tager en anden
|
||||
-- (in-game 26/9: æg-vognen kørte til Æg Pickup 4 tre gange i træk; én palle inden for rækkevidde, resten udenfor)
|
||||
local v16 = newVehicle("Thin", 0, 0, 20000)
|
||||
runs[v16] = outboundRun(16, {1, 2}, {{fillType = "SUGAR", policy = "sell"}}, {collectRound = false})
|
||||
ADOutbound.resetEmptySources()
|
||||
local choice16 = ADOutbound.choosePickup(adEnv, v16)
|
||||
local first16 = choice16.markerIndex
|
||||
local task16 = newTask(v16, choice16.markerIndex == mSilo.markerIndex and 2 or 1)
|
||||
v16.atTarget = true
|
||||
v16.trailers.level = 500
|
||||
ADOutbound.beforeLoadUpdate(adEnv, task16, 100)
|
||||
ADOutbound.beforeLoadUpdate(adEnv, task16, 16000)
|
||||
check("O16 kører med det den fik", task16.finishedCalls, 1)
|
||||
check("O16 log", lastLog("ingen mere last") ~= nil, true)
|
||||
v16.trailers.level = 0
|
||||
local choice16b = ADOutbound.choosePickup(adEnv, v16)
|
||||
check("O16 næste tur tager en anden kilde", choice16b ~= nil and choice16b.markerIndex ~= first16, true)
|
||||
ADOutbound.resetEmptySources() -- (senere tests forventer alle kilder ledige)
|
||||
|
||||
|
||||
-- O14 (I6): rutetjek kun for salgssteder over tærsklen, bedste først, stop ved første nåelige
|
||||
local routeChecks = 0
|
||||
local originalGetPathTo = adEnv.ADGraphManager.getPathTo
|
||||
@@ -613,5 +633,6 @@ do
|
||||
ADLoadSwap.findDumpMarker = dumpBefore
|
||||
end
|
||||
|
||||
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
|
||||
@@ -107,5 +107,35 @@ do
|
||||
unreachable[903], unreachable[904] = nil, nil
|
||||
end
|
||||
|
||||
-- RC: rutesvar gemmes 30 s pr. mål og 10 m-område (holdende vogne spurgte hvert 5. s -> hak hvert 5. s)
|
||||
do
|
||||
local pathCalls = 0
|
||||
local realGetPathTo = adEnv.ADGraphManager.getPathTo
|
||||
adEnv.ADGraphManager.getPathTo = function(self, vehicle, id) pathCalls = pathCalls + 1; return realGetPathTo(self, vehicle, id) end
|
||||
local clock = 0
|
||||
netGetTime = function() return clock end
|
||||
local positions = {[500] = {100, 100}}
|
||||
getWorldTranslation = function(node) local p = positions[node]; return p[1], 0, p[2] end
|
||||
local parked = {rootNode = 500, getClosestWayPoint = function() return 901, 1 end}
|
||||
ADWaitPool.hasRouteTo(adEnv, parked, 10)
|
||||
ADWaitPool.hasRouteTo(adEnv, parked, 10)
|
||||
check("RC samme svar genbruges", pathCalls, 1)
|
||||
positions[500] = {104, 103}
|
||||
ADWaitPool.hasRouteTo(adEnv, parked, 10)
|
||||
check("RC samme 10 m-område genbruges", pathCalls, 1)
|
||||
positions[500] = {160, 100}
|
||||
ADWaitPool.hasRouteTo(adEnv, parked, 10)
|
||||
check("RC nyt sted -> nyt svar", pathCalls, 2)
|
||||
clock = 31000
|
||||
ADWaitPool.hasRouteTo(adEnv, parked, 10)
|
||||
check("RC efter 30 s -> nyt svar", pathCalls, 3)
|
||||
local first = ADWaitPool.hasRouteTo(adEnv, parked, 11)
|
||||
check("RC andet mål -> nyt svar", pathCalls, 4)
|
||||
check("RC samme svar igen", ADWaitPool.hasRouteTo(adEnv, parked, 11), first)
|
||||
check("RC uden nyt kald", pathCalls, 4)
|
||||
adEnv.ADGraphManager.getPathTo = realGetPathTo
|
||||
netGetTime = nil
|
||||
end
|
||||
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
|
||||
Reference in New Issue
Block a user