5.9 KiB
Flow-tavle — implementeringsplan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Én tavle med ét flow pr. række (Vare · Fra · Til · Regel · Traktorer · Status); Fra/Til vælges som bygninger, markører findes automatisk. Faner: Flows · Lagre.
Architecture: Ny spil-adapter adBuildings.lua (bygninger + markør-opslag + cache). Modellen får bygnings-id-lister; controlleren udleder waypoint-lister fra dem (resolveMarkers) så planlægger/hooks er uændrede. GUI omskrives: SmartPickupFrame.lua (faner, tavle, fælles), SmartPickupFlowTab.lua (detail-blok), SmartPickupStorageTab.lua (uændret).
Tech Stack: FS25 Lua, AutoDrive-globaler via FS25_AutoDrive, luajit-tests.
Spec: docs/superpowers/specs/2026-09-23-flow-tavle-design.md
Global Constraints
- Motoren (adOutbound, adOutboundPlanner, adSupplyPlanner, adUnloadWait, adSmartPickup-hooks) røres ikke.
- Byg kun når alle tests er grønne (
for t in tests/test_*.lua; do luajit $t|tail -1; done), derefter zip →~/FS25-data/mods/→ commit → push gitea main. - Version 1.13.0.0. XML-version 3; v1/v2 læses.
- Wait-markører er aldrig bygningsmarkører. Siloers læssemarkør = strengt opslag; alt andet = nærmeste ≤ 40 m.
Review Focus
- Run med bygning der er solgt siden sidst: rækken viser "(mangler)", Start afviser med noMarker, intet crash. (Task 3 test)
- v2-fil med markør der ikke kan oversættes til en bygning: markøren beholdes rå og virker som før. (Task 2 test)
- To bygninger med markører inden for 40 m af hinanden (silo-rækker): hver silo får sin egen markør (strengt opslag). (Task 1 test)
- Forsynings-run: Fra vises som "alle siloer" og sources-listen røres ikke. (Task 3 test)
- Fanen rebuild'es mens et run kører: Start/Stop-knappen og status følger
isRunning. (in-game)
Task 1: adBuildings
Files: Create FS25_ADSmartPickup/adBuildings.lua; Test tests/test_adBuildings.lua.
Produces:
ADBuildings.MAX_MARKER_DISTANCE = 40; ADBuildings.CACHE_MS = 1000
ADBuildings.list(adEnv, farmId) -- {building...} sorteret kind, navn (cachet)
ADBuildings.find(adEnv, farmId, id) -- building | nil
ADBuildings.byMarker(adEnv, farmId, wayPointId, role) -- role "load"|"unload": building hvis markøren er dens markør, ellers nil
ADBuildings.getId(placeable) -- uniqueId eller "pos:x:z"
ADBuildings.invalidate()
building = {id, name, kind, placeable, loadMarker={id,name,distance}|nil, unloadMarker=…|nil, canBeSource, canBeTarget, canSell}
Kilder til bygninger: g_currentMission.placeableSystem.placeables (ejet af farm eller sell) — kind: factory (spec_productionPoint), silo (spec_silo), husbandry (getHusbandryFillLevel), objectStorage (spec_objectStorage), sell (ADPrices.isSellingStation på placeable.spec_sellingPoint / unloadingStation via storageSystem). Læssetriggere: productionPoint.loadingStation.loadTriggers, spec_silo.loadingStation.loadTriggers, husbandry: alle loadingStations i storageSystem med owningPlaceable == placeable. Aflæsningstriggere: unloadingStations med owningPlaceable == placeable. Objektlager/pallespawner: rootNode/spawnPlaces[1].startNode.
Markørvalg: nærmeste markør (ikke Wait) til en trigger-node ≤ 40 m; for silo-load: kun markører hvor ADSmartPickup.getLoadStationAtWayPointId(marker.id) == siloens station.
- Tests B1–B7 (kind, markører, silo strengt, Wait udelukket, byMarker, id-fallback, cache-invalidering) → RED → implementér → GREEN → commit
feat: adBuildings.
Task 2: Model v3
Files: Modify adRuns.lua, adRunsStorage.lua; Test tests/test_adRuns.lua.
Produces: run-felter sourceBuildingIds, targetBuildingIds (lister af strenge); ADRuns.toggleSourceBuilding/toggleTargetBuilding(store, runId, id); XML v3 #sourceBuildings/#targetBuildings (mellemrumsadskilte). ADRuns.XML_VERSION = 3. Migration sker i controlleren (Task 3), ikke i modellen.
- Tests R-v3 → RED → implementér → GREEN → commit.
Task 3: Controller — resolve + migration + validering
Files: Modify adRunsController.lua; Test tests/test_adRunsController.lua.
Produces:
ADRunsController.resolveMarkers(adEnv, run) -- udfylder run.sourceWayPointIds (outbound) / targetWayPointIds (supply) fra bygninger; rå markører (uden bygning) bevares; returnerer {missing = {buildingName...}}
ADRunsController.migrateBuildings(adEnv) -- ved load: markører → bygnings-id via byMarker; logger
ADRunsController.getFlowRow(adEnv, run) -- {product, from, to, rule, vehicles, status, warning} tekster til tavlen
validateVehicle: ny grund "noMarker" når en valgt bygning mangler markør
Start/plan: startRun og ADOutbound.buildPlanInput kalder resolveMarkers først (buildPlanInput via ADRunsController.getRunForVehicle → resolve i getRunForVehicle? nej: i ADSmartPickup.choosePickup/ADOutbound.choosePickup kaldes ADRunsController.resolveMarkers(adEnv, run) én gang pr. plan).
- Tests C-flow → RED → implementér → GREEN → commit.
Task 4: GUI — Flows-fane
Files: Rewrite gui/SmartPickupFrame.lua (faner Flows/Lagre, tavle, fælles rækker, knapper), Create gui/SmartPickupFlowTab.lua (detail-blok, callbacks), delete SmartPickupSupplyTab.lua/SmartPickupOutboundTab.lua (indhold flyttes), Modify gui/SmartPickupFrame.xml (statiske rækker: runOption "Flow", waitPool, loops, returnBelow, sellAt, storeAbove; prefabs som i dag), l10n da/en (spu_tab_flows, spu_flow_*, spu_direction_in/out, spu_from_allSilos, spu_noMarker, spu_reason_noMarker, spu_section_*), adSmartPickup.lua (source()).
- Implementér; syntaks- og definitions-tjek; in-game.