From 12d788efecc551cbd83138790164d7864039e40e Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Sat, 2 May 2020 00:27:58 -0400 Subject: [PATCH] asset: fix reading saved state The problem identified by the stack trace below is caused by the json library changing the key type to a string for both the _priority and _intel tables. Since LUA differentiates between a number and string when looking up a key in a table you can actually have a table construction like the following; { 1 = 1234, "1" = 789, } This will result in two different values being returned depending on if you asked for the key `"1"` or `1`. The solution is to turn these table keys back into numbers when reading in the state file. Stack trace: 2020-05-01 22:45:15.811 ERROR SCRIPTING: DCT|Theater: protected call - [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Asset.lua"]:149: attempt to index field '?' (a nil value) stack traceback: [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Theater.lua"]:338: in function <[string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Theater.lua"]:336> [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Asset.lua"]:149: in function 'getPriority' [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\ai\Commander.lua"]:25: in function 'heapsort_tgtlist' [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\ai\Commander.lua"]:191: in function 'requestMission' [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\ui\cmds.lua"]:171: in function '_execute' [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\ui\cmds.lua"]:48: in function 'execute' [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Theater.lua"]:318: in function '_exec' [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Theater.lua"]:341: in function <[string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Theater.lua"]:340> [C]: in function 'xpcall' [string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Theater.lua"]:344: in function <[string "C:\Saved Games\DCS.openbeta\Mods\tech\DCT\lua\dct\Theater.lua"]:335> Finally, add a unit-test to catch this issue in the future by triggering a user command after the state file has been read back in. Closes: #74 Fixes: 942e4c4d27be ("asset: use composition to represent different asset types") --- src/dct/Asset.lua | 10 ++++++++++ tests/test-theater.lua | 27 ++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/dct/Asset.lua b/src/dct/Asset.lua index 80d3d7c6..0587b129 100644 --- a/src/dct/Asset.lua +++ b/src/dct/Asset.lua @@ -236,6 +236,16 @@ function Asset:unmarshal(data) local collectiondata = data.collection data.collection = nil utils.mergetables(self, data) + -- need to handle the intel and priority tables special because even + -- though their keys were numbers when the state was serialized + -- in json's wisdom it decided to convert them to strings. So we need to + -- convert back so we can access the data in our lookups. + for _, tbl in ipairs({"_intel", "_priority"}) do + self[tbl] = {} + for k, v in pairs(data[tbl]) do + self[tbl][tonumber(k)] = v + end + end self._collection = getcollection(data.type, self) self._collection:unmarshal(collectiondata) self._initcomplete = true diff --git a/tests/test-theater.lua b/tests/test-theater.lua index 0721a296..117b4e78 100755 --- a/tests/test-theater.lua +++ b/tests/test-theater.lua @@ -5,6 +5,7 @@ require("io") local md5 = require("md5") require("dcttestlibs") require("dct") +local enum = require("dct.enum") local settings = _G.dct.settings local events = { @@ -204,7 +205,7 @@ end local function main() local playergrp = Group(4, { ["id"] = 15, - ["name"] = "Uzi 35", + ["name"] = "Uzi 41", ["coalition"] = coalition.side.BLUE, ["exists"] = true, }) @@ -242,6 +243,30 @@ local function main() -- verify the units read in do not include the asset we killed off assert(newtheater:getAssetMgr():getAsset(name) == nil, "state saving has an issue") + + -- attempt to get theater status + newtheater:onEvent({ + ["id"] = world.event.S_EVENT_BIRTH, + ["initiator"] = player1, + }) + + local status = { + ["data"] = { + ["name"] = playergrp:getName(), + ["type"] = enum.uiRequestType.THEATERSTATUS, + }, + ["assert"] = true, + ["expected"] = "== Theater Threat Status ==\n Sea: medium\n".. + " Air: parity\n ELINT: medium\n SAM: medium\n\n".. + "== Current Active Air Missions ==\n No Active Missions\n\n".. + "Recommended Mission Type: CAP\n", + } + local uicmds = require("dct.ui.cmds") + trigger.action.setassert(status.assert) + trigger.action.setmsgbuffer(status.expected) + local cmd = uicmds[status.data.type](newtheater, status.data) + cmd:execute(400) + newtheater:export() f = io.open(settings.statepath, "r") local sumsave = md5.sum(f:read("*all"))