feat: runs gemmes i savegameN/ADSmartPickup_runs.xml

This commit is contained in:
2026-09-22 22:21:30 +02:00
parent e4d131b827
commit b9832a8af8
2 changed files with 163 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
-- AD Runs Storage
-- Runs gemmes i savegame-mappen ved siden af AutoDrive_config.xml. Kun dette lag
-- kender XMLFile; modellen (adRuns) ser kun flade poster.
ADRunsStorage = {}
ADRunsStorage.FILE_NAME = "ADSmartPickup_runs.xml"
ADRunsStorage.ROOT = "ADSmartPickupRuns"
ADRunsStorage.LOG_PREFIX = "ADSmartPickup: "
-- Samme opslag som AutoDrive.getXMLFile_new: mappen kendes efter første gem, ellers via indeks.
function ADRunsStorage.getPath()
local info = g_currentMission ~= nil and g_currentMission.missionInfo or nil
if info == nil then
return nil
end
if info.savegameDirectory ~= nil then
return info.savegameDirectory .. "/" .. ADRunsStorage.FILE_NAME
end
if info.savegameIndex ~= nil and getUserProfileAppPath ~= nil then
return getUserProfileAppPath() .. "savegame" .. tostring(info.savegameIndex) .. "/" .. ADRunsStorage.FILE_NAME
end
return nil
end
function ADRunsStorage.writeRecords(xmlFile, records)
xmlFile:setInt(ADRunsStorage.ROOT .. "#version", ADRuns.XML_VERSION)
for index, record in ipairs(records) do
local key = string.format("%s.run(%d)", ADRunsStorage.ROOT, index - 1)
xmlFile:setInt(key .. "#id", record.id)
xmlFile:setString(key .. "#name", record.name)
xmlFile:setInt(key .. "#target", record.target)
xmlFile:setString(key .. "#ingredientMode", record.ingredientMode)
xmlFile:setString(key .. "#ingredients", record.ingredients)
xmlFile:setString(key .. "#waitPool", record.waitPool)
xmlFile:setInt(key .. "#loops", record.loops)
for vehicleIndex, vehicleId in ipairs(record.vehicleIds) do
xmlFile:setString(string.format("%s.vehicle(%d)#id", key, vehicleIndex - 1), vehicleId)
end
end
end
function ADRunsStorage.readRecords(xmlFile)
local records = {}
xmlFile:iterate(ADRunsStorage.ROOT .. ".run", function(_, key)
local record = {
id = xmlFile:getInt(key .. "#id"),
name = xmlFile:getString(key .. "#name"),
target = xmlFile:getInt(key .. "#target"),
ingredientMode = xmlFile:getString(key .. "#ingredientMode"),
ingredients = xmlFile:getString(key .. "#ingredients"),
waitPool = xmlFile:getString(key .. "#waitPool"),
loops = xmlFile:getInt(key .. "#loops"),
vehicleIds = {},
}
xmlFile:iterate(key .. ".vehicle", function(_, vehicleKey)
local id = xmlFile:getString(vehicleKey .. "#id")
if id ~= nil and id ~= "" then
table.insert(record.vehicleIds, id)
end
end)
table.insert(records, record)
end)
return records
end
function ADRunsStorage.save(store)
local path = ADRunsStorage.getPath()
if path == nil then
return false
end
local xmlFile = XMLFile.create("ADSmartPickupRuns", path, ADRunsStorage.ROOT)
if xmlFile == nil then
Logging.warning(ADRunsStorage.LOG_PREFIX .. "kunne ikke oprette %s", path)
return false
end
ADRunsStorage.writeRecords(xmlFile, ADRuns.toRecords(store))
xmlFile:save()
xmlFile:delete()
return true
end
function ADRunsStorage.load()
local path = ADRunsStorage.getPath()
if path == nil or not fileExists(path) then
return ADRuns.newStore()
end
local xmlFile = XMLFile.load("ADSmartPickupRuns", path)
if xmlFile == nil then
Logging.warning(ADRunsStorage.LOG_PREFIX .. "kunne ikke læse %s; starter uden runs", path)
return ADRuns.newStore()
end
local records = ADRunsStorage.readRecords(xmlFile)
xmlFile:delete()
return ADRuns.fromRecords(records)
end
+67
View File
@@ -96,5 +96,72 @@ check("R6 nextId", dirty.nextId, 8)
check("R6 tom liste", #ADRuns.fromRecords(nil).runs, 0)
check("R6 parseIngredients trimmer", #ADRuns.parseIngredients(" STRAW FORAGE "), 2)
-- ==== XML-laget mod en flad XMLFile-mock (nøgle -> værdi) ====
dofile("FS25_ADSmartPickup/adRunsStorage.lua")
local function makeXmlMock(values)
local xml = {values = values or {}, saved = false, deleted = false}
xml.setInt = function(self, key, value) self.values[key] = value end
xml.setString = function(self, key, value) self.values[key] = value end
xml.getInt = function(self, key) return tonumber(self.values[key]) end
xml.getString = function(self, key) local v = self.values[key]; return v ~= nil and tostring(v) or nil end
-- iterate: kalder callback for "prefix(0)", "prefix(1)", ... så længe en nøgle med den stamme findes
xml.iterate = function(self, prefix, callback)
local index = 0
while true do
local key = string.format("%s(%d)", prefix, index)
local found = false
for k in pairs(self.values) do
if k:sub(1, #key) == key then found = true break end
end
if not found then return end
callback(index + 1, key)
index = index + 1
end
end
xml.save = function(self) self.saved = true end
xml.delete = function(self) self.deleted = true end
return xml
end
-- X1: records skrives som attributter + vehicle-underelementer
local out = makeXmlMock()
ADRunsStorage.writeRecords(out, ADRuns.toRecords(s5))
check("X1 version", out.values["ADSmartPickupRuns#version"], 1)
check("X1 run 0 navn", out.values["ADSmartPickupRuns.run(0)#name"], "Cow 1")
check("X1 run 0 target", out.values["ADSmartPickupRuns.run(0)#target"], 94)
check("X1 run 0 varer", out.values["ADSmartPickupRuns.run(0)#ingredients"], "STRAW FORAGE")
check("X1 run 0 pulje", out.values["ADSmartPickupRuns.run(0)#waitPool"], "Cow Wait")
check("X1 run 1 køretøj", out.values["ADSmartPickupRuns.run(1).vehicle(0)#id"], "vehicleA")
-- X2: samme data læses tilbage
local records2 = ADRunsStorage.readRecords(makeXmlMock(out.values))
check("X2 to poster", #records2, 2)
check("X2 id", records2[1].id, 1)
check("X2 køretøj", records2[2].vehicleIds[1], "vehicleA")
check("X2 loops", records2[1].loops, 99)
check("X2 round-trip", ADRuns.findRunByVehicle(ADRuns.fromRecords(records2), "vehicleA").id, 2)
-- X3: save/load via XMLFile-globalen; ingen savegame-mappe -> tom store, intet skrives
Logging = Logging or {warning = function() end, info = function() end}
local created, loaded = nil, nil
XMLFile = {
create = function(_, path, root) created = makeXmlMock(); created.path = path; created.root = root; return created end,
load = function(_, path) loaded = makeXmlMock(created and created.values or {}); loaded.path = path; return loaded end,
}
fileExists = function(path) return created ~= nil and created.path == path end
g_currentMission = {missionInfo = {savegameDirectory = "/tmp/sg1"}}
check("X3 gemt", ADRunsStorage.save(s5), true)
check("X3 sti", created.path, "/tmp/sg1/ADSmartPickup_runs.xml")
check("X3 rodelement", created.root, "ADSmartPickupRuns")
check("X3 save+delete kaldt", created.saved and created.deleted, true)
check("X3 indlæst", #ADRunsStorage.load().runs, 2)
check("X3 læse-handle lukket", loaded.deleted, true)
g_currentMission = {missionInfo = {}}
check("X3 uden savegame -> false", ADRunsStorage.save(s5), false)
check("X3 uden savegame -> tom store", #ADRunsStorage.load().runs, 0)
g_currentMission = {missionInfo = {savegameDirectory = "/tmp/sg-ny"}}
check("X3 fil mangler -> tom store", #ADRunsStorage.load().runs, 0)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)