fix: slut-review — pcall om start/dialoger, Auto-varer fra aktivt AD-mål, nil-guards, README
This commit is contained in:
@@ -53,6 +53,8 @@ function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointI
|
|||||||
local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId)
|
local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId)
|
||||||
if station ~= nil and isSilo(station, homeStation) and acceptsRest(station, fillType, rest, farmId) then
|
if station ~= nil and isSilo(station, homeStation) and acceptsRest(station, fillType, rest, farmId) then
|
||||||
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id)
|
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
|
local dx, dz = wayPoint.x - x, wayPoint.z - z
|
||||||
table.insert(candidates, {
|
table.insert(candidates, {
|
||||||
marker = marker,
|
marker = marker,
|
||||||
@@ -61,6 +63,7 @@ function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointI
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
table.sort(candidates, function(a, b)
|
table.sort(candidates, function(a, b)
|
||||||
if a.hasFillType ~= b.hasFillType then
|
if a.hasFillType ~= b.hasFillType then
|
||||||
return a.hasFillType
|
return a.hasFillType
|
||||||
|
|||||||
@@ -112,7 +112,20 @@ end
|
|||||||
-- findSupplyPickup selv til de ønskede produktioners inputs bagefter.
|
-- findSupplyPickup selv til de ønskede produktioners inputs bagefter.
|
||||||
function ADRunsController.getTargetFillTypes(adEnv, run, vehicle)
|
function ADRunsController.getTargetFillTypes(adEnv, run, vehicle)
|
||||||
local farmId = ADSmartPickup.getFarmId(vehicle)
|
local farmId = ADSmartPickup.getFarmId(vehicle)
|
||||||
local target = run.targetWayPointId ~= nil and ADSmartPickup.getUnloadStationAtWayPointId(adEnv, run.targetWayPointId, farmId) or nil
|
-- En kørende traktor følger AD's eget mål (stateModule:getSecondMarker(), det samme
|
||||||
|
-- choosePickup/findSupplyPickup bruger) indtil næste Start — IKKE run'ets gemte
|
||||||
|
-- targetWayPointId. Redigerer brugeren run'ets Mål mens tildelte traktorer kører,
|
||||||
|
-- skal Auto-listen derfor følge det LIVE mål, ellers kan den blive tom og fejlagtigt
|
||||||
|
-- smide traktoren over i mappe-logikken midt i turen.
|
||||||
|
local wayPointId = run.targetWayPointId
|
||||||
|
local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil
|
||||||
|
if stateModule ~= nil and stateModule.isActive ~= nil and stateModule:isActive() and stateModule.getSecondMarker ~= nil then
|
||||||
|
local secondMarker = stateModule:getSecondMarker()
|
||||||
|
if secondMarker ~= nil and secondMarker.id ~= nil then
|
||||||
|
wayPointId = secondMarker.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local target = wayPointId ~= nil and ADSmartPickup.getUnloadStationAtWayPointId(adEnv, wayPointId, farmId) or nil
|
||||||
if target == nil then
|
if target == nil then
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
@@ -251,6 +264,9 @@ local function findNearestLoadMarker(adEnv, vehicle, farmId)
|
|||||||
for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do
|
for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do
|
||||||
if ADSmartPickup.getLoadStationAtWayPointId(adEnv, marker.id, farmId) ~= nil then
|
if ADSmartPickup.getLoadStationAtWayPointId(adEnv, marker.id, farmId) ~= nil then
|
||||||
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id)
|
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id)
|
||||||
|
-- En stale markør uden waypoint skal springes over — ellers fejler Start med "error"
|
||||||
|
-- for ALLE tildelte traktorer, ikke kun den der ramte den ugyldige markør.
|
||||||
|
if wayPoint ~= nil then
|
||||||
local dx, dz = wayPoint.x - x, wayPoint.z - z
|
local dx, dz = wayPoint.x - x, wayPoint.z - z
|
||||||
local distance = dx * dx + dz * dz
|
local distance = dx * dx + dz * dz
|
||||||
if distance < bestDistance then
|
if distance < bestDistance then
|
||||||
@@ -258,6 +274,7 @@ local function findNearestLoadMarker(adEnv, vehicle, farmId)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
return best
|
return best
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -284,6 +301,16 @@ local function isVehicleActive(vehicle)
|
|||||||
return stateModule ~= nil and stateModule.isActive ~= nil and stateModule:isActive()
|
return stateModule ~= nil and stateModule.isActive ~= nil and stateModule:isActive()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Anvend run-tilstand OG start traktoren i ét pcall'et kald: kaster vehicle:startAutoDrive()
|
||||||
|
-- (fx AD's egen validering), skal den ene traktor fejle uden at hele startRun-loopet
|
||||||
|
-- afbrydes — ellers når de øvrige tildelte traktorer aldrig at blive startet.
|
||||||
|
local function applyAndStart(adEnv, run, vehicle, ingredients)
|
||||||
|
applyRunToVehicle(adEnv, run, vehicle, ingredients)
|
||||||
|
if not isVehicleActive(vehicle) then
|
||||||
|
vehicle:startAutoDrive()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Pr. tildelt traktor: validér, skriv AD-tilstand, start. ✖-traktorer springes over.
|
-- Pr. tildelt traktor: validér, skriv AD-tilstand, start. ✖-traktorer springes over.
|
||||||
function ADRunsController.startRun(adEnv, runId)
|
function ADRunsController.startRun(adEnv, runId)
|
||||||
local run = ADRuns.getRun(ADRunsController.store, runId)
|
local run = ADRuns.getRun(ADRunsController.store, runId)
|
||||||
@@ -299,11 +326,8 @@ function ADRunsController.startRun(adEnv, runId)
|
|||||||
local result = {vehicle = vehicle, ok = validation.ok, reason = validation.reason}
|
local result = {vehicle = vehicle, ok = validation.ok, reason = validation.reason}
|
||||||
if validation.ok then
|
if validation.ok then
|
||||||
local ingredients = ADRunsController.getRunIngredients(adEnv, run, vehicle)
|
local ingredients = ADRunsController.getRunIngredients(adEnv, run, vehicle)
|
||||||
local ok, err = pcall(applyRunToVehicle, adEnv, run, vehicle, ingredients)
|
local ok, err = pcall(applyAndStart, adEnv, run, vehicle, ingredients)
|
||||||
if ok then
|
if ok then
|
||||||
if not isVehicleActive(vehicle) then
|
|
||||||
vehicle:startAutoDrive()
|
|
||||||
end
|
|
||||||
Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' startet mod markør %s", tostring(run.name), tostring(vehicle:getName()), tostring(run.targetWayPointId))
|
Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' startet mod markør %s", tostring(run.name), tostring(vehicle:getName()), tostring(run.targetWayPointId))
|
||||||
else
|
else
|
||||||
result.ok, result.reason = false, "error"
|
result.ok, result.reason = false, "error"
|
||||||
|
|||||||
@@ -424,9 +424,13 @@ function SmartPickupFrame:onClickNew()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SmartPickupFrame:onClickRename()
|
function SmartPickupFrame:onClickRename()
|
||||||
local run = self:getRun()
|
-- Dialogen kan kaste (fx manglende i18n-nøgle) — fang det som resten af GUI'et, i stedet
|
||||||
|
-- for at lade fejlen undslippe klik-callbacken uden statuslinje-besked.
|
||||||
|
self:safe(function(frame)
|
||||||
|
local run = frame:getRun()
|
||||||
if run == nil then return end
|
if run == nil then return end
|
||||||
TextInputDialog.show(SmartPickupFrame.onRenameResult, self, run.name, self.i18n:getText("spu_renameTitle"), nil, 30, g_i18n:getText("button_ok"))
|
TextInputDialog.show(SmartPickupFrame.onRenameResult, frame, run.name, frame.i18n:getText("spu_renameTitle"), nil, 30, g_i18n:getText("button_ok"))
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SmartPickupFrame:onRenameResult(value, clickOk)
|
function SmartPickupFrame:onRenameResult(value, clickOk)
|
||||||
@@ -440,9 +444,12 @@ function SmartPickupFrame:onRenameResult(value, clickOk)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SmartPickupFrame:onClickDelete()
|
function SmartPickupFrame:onClickDelete()
|
||||||
local run = self:getRun()
|
-- Samme begrundelse som onClickRename: dialog-opkaldet skal ikke kunne undslippe uden om safe().
|
||||||
|
self:safe(function(frame)
|
||||||
|
local run = frame:getRun()
|
||||||
if run == nil then return end
|
if run == nil then return end
|
||||||
YesNoDialog.show(SmartPickupFrame.onDeleteResult, self, string.format(self.i18n:getText("spu_deleteConfirm"), run.name), self.i18n:getText("spu_button_delete"))
|
YesNoDialog.show(SmartPickupFrame.onDeleteResult, frame, string.format(frame.i18n:getText("spu_deleteConfirm"), run.name), frame.i18n:getText("spu_button_delete"))
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SmartPickupFrame:onDeleteResult(yes)
|
function SmartPickupFrame:onDeleteResult(yes)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
<text name="spu_vehicle_tooltip" text="Ja = traktoren er med i dette run."/>
|
<text name="spu_vehicle_tooltip" text="Ja = traktoren er med i dette run."/>
|
||||||
<text name="spu_waitPools" text="Wait-puljer"/>
|
<text name="spu_waitPools" text="Wait-puljer"/>
|
||||||
<text name="spu_waitPoolRow" text="%s — %d punkter — %d optaget%s"/>
|
<text name="spu_waitPoolRow" text="%s — %d punkter — %d optaget%s"/>
|
||||||
<text name="spu_status" text="Status"/>
|
|
||||||
<text name="spu_status_running" text="Kører (%d/%d)"/>
|
<text name="spu_status_running" text="Kører (%d/%d)"/>
|
||||||
<text name="spu_status_stopped" text="Stoppet (%d traktorer)"/>
|
<text name="spu_status_stopped" text="Stoppet (%d traktorer)"/>
|
||||||
<text name="spu_status_started" text="Startet %d, sprunget over %d"/>
|
<text name="spu_status_started" text="Startet %d, sprunget over %d"/>
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
<text name="spu_vehicle_tooltip" text="Yes = the tractor belongs to this run."/>
|
<text name="spu_vehicle_tooltip" text="Yes = the tractor belongs to this run."/>
|
||||||
<text name="spu_waitPools" text="Wait pools"/>
|
<text name="spu_waitPools" text="Wait pools"/>
|
||||||
<text name="spu_waitPoolRow" text="%s — %d points — %d occupied%s"/>
|
<text name="spu_waitPoolRow" text="%s — %d points — %d occupied%s"/>
|
||||||
<text name="spu_status" text="Status"/>
|
|
||||||
<text name="spu_status_running" text="Running (%d/%d)"/>
|
<text name="spu_status_running" text="Running (%d/%d)"/>
|
||||||
<text name="spu_status_stopped" text="Stopped (%d tractors)"/>
|
<text name="spu_status_stopped" text="Stopped (%d tractors)"/>
|
||||||
<text name="spu_status_started" text="Started %d, skipped %d"/>
|
<text name="spu_status_started" text="Started %d, skipped %d"/>
|
||||||
|
|||||||
@@ -97,7 +97,9 @@ startes/stoppes samlet for alle traktorer i det.
|
|||||||
- **Ture** — loop-tælleren (0–99, 0 = uendeligt), som normalt i AutoDrives Pickup&Deliver.
|
- **Ture** — loop-tælleren (0–99, 0 = uendeligt), som normalt i AutoDrives Pickup&Deliver.
|
||||||
- **Traktorer** — rækker med Ja/Nej (er traktoren med i run'et), kapacitet og et ✔/✖-ikon. En
|
- **Traktorer** — rækker med Ja/Nej (er traktoren med i run'et), kapacitet og et ✔/✖-ikon. En
|
||||||
**✖-traktor springes over ved Start**, med en grund vist ved siden af (fx "ingen vogn", "vognen
|
**✖-traktor springes over ved Start**, med en grund vist ved siden af (fx "ingen vogn", "vognen
|
||||||
kan ikke bære run'ets varer", "for langt fra vejnettet" eller "intet mål").
|
kan ikke bære run'ets varer", "for langt fra vejnettet" eller "intet mål"). Sættes en traktor til
|
||||||
|
Nej (fjernet fra run'et), rører det IKKE dens AutoDrive-vareliste — run'ets varer forbliver valgt
|
||||||
|
i traktorens AD-vareliste (synlig/redigerbar i AD's eget HUD) indtil de ændres dér manuelt.
|
||||||
|
|
||||||
**Start/Stop:** "Start run" sætter AutoDrive op på hver ✔-traktor: mode Pickup&Deliver, målmarkør,
|
**Start/Stop:** "Start run" sætter AutoDrive op på hver ✔-traktor: mode Pickup&Deliver, målmarkør,
|
||||||
nærmeste pålæsningsmarkør som start, run'ets varer valgt, run'ets tur-tæller, mapper ("Brug mapper")
|
nærmeste pålæsningsmarkør som start, run'ets varer valgt, run'ets tur-tæller, mapper ("Brug mapper")
|
||||||
@@ -107,8 +109,8 @@ traktorens hidtidige manuelle AutoDrive-indstillinger.** "Stop run" stopper Auto
|
|||||||
i run'et (medlemskabet i run'et bevares, så det kan startes igen). Traktorer der ikke er del af noget
|
i run'et (medlemskabet i run'et bevares, så det kan startes igen). Traktorer der ikke er del af noget
|
||||||
run, kører som før — bortset fra at "Brug mapper" kan være blevet slået til globalt af et run.
|
run, kører som før — bortset fra at "Brug mapper" kan være blevet slået til globalt af et run.
|
||||||
|
|
||||||
**Wait-puljer-fanen** viser hver Wait-mappe skrivebeskyttet: antal punkter og hvilken traktor der
|
**Wait-puljer-afsnittet** nederst på siden viser hver Wait-mappe skrivebeskyttet: antal punkter og
|
||||||
holder hvor.
|
hvilken traktor der holder hvor.
|
||||||
|
|
||||||
**Gemning:** Runs gemmes i `savegameN/ADSmartPickup_runs.xml` (ved gem og ved Start/Stop). De
|
**Gemning:** Runs gemmes i `savegameN/ADSmartPickup_runs.xml` (ved gem og ved Start/Stop). De
|
||||||
**genstartes ikke automatisk** ved indlæsning af et savegame — kør "Start run" igen efter load, hvis
|
**genstartes ikke automatisk** ved indlæsning af et savegame — kør "Start run" igen efter load, hvis
|
||||||
@@ -144,7 +146,8 @@ aldrig fejlagtigt bliver opfattet som et fuldt mål.
|
|||||||
- Wrapper `ADMultipleTargetsManager.getNextPickup` (via den globale `FS25_AutoDrive`-tabel); rører ikke AutoDrive-zip'en.
|
- Wrapper `ADMultipleTargetsManager.getNextPickup` (via den globale `FS25_AutoDrive`-tabel); rører ikke AutoDrive-zip'en.
|
||||||
- Siloens eget lager rangeres før nabo-lån (udvidelses-siloer deler lager inden for `storageRadius`).
|
- Siloens eget lager rangeres før nabo-lån (udvidelses-siloer deler lager inden for `storageRadius`).
|
||||||
- Intet fund, intet behov eller fejl i et spil-API → AutoDrives originale rotation. Valg logges som `ADSmartPickup:` i log.txt.
|
- Intet fund, intet behov eller fejl i et spil-API → AutoDrives originale rotation. Valg logges som `ADSmartPickup:` i log.txt.
|
||||||
- Kræver i AutoDrive: "Brug mapper" + "Rotér mål: pålæsning" på køretøjet.
|
- Kræver i AutoDrive: "Brug mapper" (global AutoDrive-indstilling, gælder hele spillet) +
|
||||||
|
"Rotér mål: pålæsning" på køretøjet (pr. køretøj).
|
||||||
- **Markør ↔ silo (v1.3):** markøren er dér hvor trækkerens næse stopper; vognen holder et vogntog
|
- **Markør ↔ silo (v1.3):** markøren er dér hvor trækkerens næse stopper; vognen holder et vogntog
|
||||||
bagved. Markørens silo er derfor nærmeste trigger **bag næsen** set i ankomstretningen (forrige
|
bagved. Markørens silo er derfor nærmeste trigger **bag næsen** set i ankomstretningen (forrige
|
||||||
waypoint), højst 2 m foran. I tætte rækker (15 m mellem siloerne) er nabosiloens trigger ellers
|
waypoint), højst 2 m foran. I tætte rækker (15 m mellem siloerne) er nabosiloens trigger ellers
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ local function makeVehicle(uniqueId, name, carriable, capacity, x, z)
|
|||||||
stateModule.raiseDirtyFlag = function(self) self.dirtyCount = self.dirtyCount + 1 end
|
stateModule.raiseDirtyFlag = function(self) self.dirtyCount = self.dirtyCount + 1 end
|
||||||
stateModule.setLoopsDone = function(self, n) self.loopsDone = n end
|
stateModule.setLoopsDone = function(self, n) self.loopsDone = n end
|
||||||
stateModule.isActive = function(self) return self.active end
|
stateModule.isActive = function(self) return self.active end
|
||||||
|
-- Bruges af C13: getTargetFillTypes skal følge AD's LIVE mål (mock'er AD's eget getSecondMarker).
|
||||||
|
stateModule.getSecondMarker = function(self) return self.secondMarkerId ~= nil and {id = self.secondMarkerId} or nil end
|
||||||
local vehicle = {
|
local vehicle = {
|
||||||
uniqueId = uniqueId, farmId = 1, rootNode = uniqueId,
|
uniqueId = uniqueId, farmId = 1, rootNode = uniqueId,
|
||||||
carriable = carriable, trailers = {level = 0, capacity = capacity},
|
carriable = carriable, trailers = {level = 0, capacity = capacity},
|
||||||
@@ -253,6 +255,41 @@ check("C11 global rotateTargets urørt", adEnv.AutoDrive.settings.rotateTargets.
|
|||||||
check("C11 useFolders global stadig skrevet", adEnv.AutoDrive.settings.useFolders.current, 2)
|
check("C11 useFolders global stadig skrevet", adEnv.AutoDrive.settings.useFolders.current, 2)
|
||||||
check("C11 køretøjet startet", noSettings.started, 1)
|
check("C11 køretøjet startet", noSettings.started, 1)
|
||||||
|
|
||||||
|
-- C12: startAutoDrive() kaster for én traktor -> pcall'et applyAndStart fanger fejlen,
|
||||||
|
-- resultatet markeres ok=false/reason="error", og de ØVRIGE traktorer i run'et startes stadig
|
||||||
|
-- (fejlen må ikke undslippe startRun-loopet).
|
||||||
|
buildWorld()
|
||||||
|
local brokenRun = ADRunsController.createRun("Broken Start")
|
||||||
|
ADRunsController.updateRun(brokenRun.id, {targetWayPointId = 94, loops = 2})
|
||||||
|
local broken = makeVehicle("vehicleBroken", "Fejl-traktor", {STRAW, TMR}, 500000, 100, 0)
|
||||||
|
broken.startAutoDrive = function() error("boom") end
|
||||||
|
local normal = makeVehicle("vehicleNormal", "Normal-traktor", {STRAW, TMR}, 500000, 200, 0)
|
||||||
|
ADRunsController.assignVehicle(brokenRun.id, broken)
|
||||||
|
ADRunsController.assignVehicle(brokenRun.id, normal)
|
||||||
|
local c12Results = ADRunsController.startRun(adEnv, brokenRun.id)
|
||||||
|
check("C12 to resultater", #c12Results, 2)
|
||||||
|
check("C12 fejl-traktor ok=false", c12Results[1].ok, false)
|
||||||
|
check("C12 fejl-traktor reason=error", c12Results[1].reason, "error")
|
||||||
|
check("C12 fejl-traktor ikke startet", broken.started, nil)
|
||||||
|
check("C12 normal-traktor ok=true", c12Results[2].ok, true)
|
||||||
|
check("C12 normal-traktor startet", normal.started, 1)
|
||||||
|
|
||||||
|
-- C13: Auto-listen følger traktorens LIVE AD-mål (stateModule:getSecondMarker()) mens den kører,
|
||||||
|
-- IKKE run'ets gemte targetWayPointId — ellers afviger listen fra det choosePickup/findSupplyPickup
|
||||||
|
-- faktisk bruger, hvis brugeren redigerer run'ets Mål mens traktoren kører.
|
||||||
|
addMarker(95, "Alt Cow Food", "Cow Food", 5300, 0)
|
||||||
|
unloadAt[95] = {accepts = {[STRAW] = 1000}}
|
||||||
|
local liveRun = ADRunsController.createRun("Live Target")
|
||||||
|
ADRunsController.updateRun(liveRun.id, {targetWayPointId = 94})
|
||||||
|
local liveRunData = ADRuns.getRun(ADRunsController.store, liveRun.id)
|
||||||
|
local liveVehicle = makeVehicle("vehicleLive", "Live-traktor", {STRAW, TMR}, 500000, 300, 0)
|
||||||
|
check("C13 inaktiv: auto-liste fra run'ets mål (94)", table.concat(ADRunsController.getRunIngredients(adEnv, liveRunData, liveVehicle), ","), STRAW .. "," .. TMR)
|
||||||
|
liveVehicle.ad.stateModule.active = true
|
||||||
|
liveVehicle.ad.stateModule.secondMarkerId = 95
|
||||||
|
check("C13 aktiv: auto-liste fra AD's live mål (95)", table.concat(ADRunsController.getRunIngredients(adEnv, liveRunData, liveVehicle), ","), tostring(STRAW))
|
||||||
|
liveVehicle.ad.stateModule.active = false
|
||||||
|
liveVehicle.ad.stateModule.secondMarkerId = nil
|
||||||
|
|
||||||
-- C10: målets accepterede varer (til afkrydsning i GUI'et) + køretøjs-label
|
-- C10: målets accepterede varer (til afkrydsning i GUI'et) + køretøjs-label
|
||||||
buildWorld()
|
buildWorld()
|
||||||
local labelA = makeVehicle("vehicleA", "Fastrac A", {STRAW, TMR}, 1000000)
|
local labelA = makeVehicle("vehicleA", "Fastrac A", {STRAW, TMR}, 1000000)
|
||||||
|
|||||||
Reference in New Issue
Block a user