# Topic: Scenarios: File I/O

 GunChleoc Joined: 2013-10-07, 15:56 Posts: 3159 One Elder of Players Location: RenderedRect Posted at: 2018-04-28, 16:59 Can you provide me with the scenario that you are using for testing your branch? Busy indexing nil values Top Quote ypopezios Joined: 2018-04-20, 00:22 Posts: 220 Widelands-Forum-Junkie Posted at: 2018-04-28, 21:13 GunChleoc wrote: good players should still end up with a slight advantage as a reward, but not too much I'm not sure if the following is relevant, but I thought of sharing it. I understand the above desire as to bound a value between an acceptable range, so as it's not too big a dis/advantage. For any quantity which can have any value (val) between 0 and infinity, instead of comparing it against the desired bounds (minval and maxval) and equal all excessive values to them, we could bound it in a more challenging way through the following formula: ``````fairval = minval + val * (maxval - minval) / (val + maxval - minval) `````` Suppose that we want to bound a quantity between 40 and 60. The common way through comparisons would behave like this: All values less than 40 will become 40. All values between 40 and 60 will stay as they are. All values greater than 60 will become 60. While the formula would behave like this: A 0 value will become 40. All values between 0 and 780 will get compressed within 40 and 60 in a way of increasing difficulty. Any value above 780 will round to 60. If the central idea is relevant, the formula could be adjusted to bring its behavior closer to more special desires. Top Quote Nordfriese Joined: 2017-01-17, 18:07 Posts: 699 One Elder of Players Location: 0x55555d3a34c0 Posted at: 2018-04-29, 09:13 Can you provide me with the scenario that you are using for testing your branch? Here´s my test script: ``````local game = wl.Game() print("Starting to WRITE...") game:save_campaign_data("TestCampaign", "test_scenario", { abc = "Hello", d = 8, efg = "World", h = -999, i = true, jklmno = 0, pq = "Hello", rstuv = 999, wxyz = false }) print("Done.") print("Starting to READ...") local result = game:read_campaign_data("TestCampaign", "test_scenario") print("Returned:") if result == nil then print ("") else print (" " .. #result .. " item(s)") for k,v in ipairs(result) do print (" " .. k .. " = " .. v) end end print("Done.") `````` The desired output would be ``````Returned: 9 item(s) abc = "Hello", d = 8, efg = "World", h = -999, i = true, jklmno = 0, pq = "Hello", rstuv = 999, wxyz = false `````` But I always get: ``````Returned: 0 item(s) `````` The .wcd file is written to correctly, though in wrong order. @ypopezios: That´s a very good idea! I was going to use 1/x or exp(-x) functions to balance difficulties, but your approach will work much better (the only difficulty in scripting will be finding good min/max values). I´ll definitely use it in scenario #4 (though it will be some time until even #3 is complete…) Top Quote GunChleoc Joined: 2013-10-07, 15:56 Posts: 3159 One Elder of Players Location: RenderedRect Posted at: 2018-04-29, 17:34 Thanks for the formula The C++ code was actually correct, except for some test output that caused it to push strings instead of numbers. Lua is a bit tricky when your tables don't have integer keys: You can't count the number of items You have to iterate with `pairs` instead of `ipairs`. Order of keys is not stable, so don't waste your time trying to get them back in the same order that you wrote them I have fixed up your test script and added it to the test suite, in the `plain.wmf` map. You can run it to see the console output like this: ``````./widelands --verbose=true --datadir=data --datadir_for_testing=. --disable_fx=true --disable_music=true --language=en_US --scenario=test/maps/plain.wmf --script=test/maps/plain.wmf/scripting/test_campaign_data.lua `````` You're doing a good job here venturing into C++ Edited: 2018-04-29, 17:36 Busy indexing nil values Top Quote Nordfriese Joined: 2017-01-17, 18:07 Posts: 699 One Elder of Players Location: 0x55555d3a34c0 Posted at: 2018-05-02, 12:29 I hate spending so much time debugging my code when only the test script is wrong… now it works. Thanks I pulled out the code that parses/creates the table into a recursive read/write function, so tables can now be used as values. Scenarios can save subtables, e.g. ``````game:save_campaign_data("test_campaign", "test_scenario", { a_key = 0, another_key = { a = 0, b = "abc", c = { a = 4, b = false, xxx = {}, yyy = "Hello", zzz = { key1 = "Hello", key2 = "You", key3 = "World", key4 = "!", subtbl = { ... }, also_a_subtable = { ... } } } } }) `````` One other thing it would be nice to have is to permit arrays as well as tables. Using an array currently causes a coroutine error ("invalid key to 'next'"). I don´t know how to fix that though… Top Quote GunChleoc Joined: 2013-10-07, 15:56 Posts: 3159 One Elder of Players Location: RenderedRect Posted at: 2018-05-03, 08:46 Nordfriese wrote: I hate spending so much time debugging my code when only the test script is wrong… now it works. Thanks Yep. It led me a merry chase too I pulled out the code that parses/creates the table into a recursive read/write function, so tables can now be used as values. Scenarios can save subtables Very nice! One other thing it would be nice to have is to permit arrays as well as tables. Using an array currently causes a coroutine error ("invalid key to 'next'"). I don´t know how to fix that though… What do you mean by that - tables that use ints instead of strings as keys? I guess you'd have to iterate over the current table to check if all keys can be reverted to consecutive ints, starting from 1. This check could be done when saving if you write a hint to the file, or during loading. Busy indexing nil values Top Quote Nordfriese Joined: 2017-01-17, 18:07 Posts: 699 One Elder of Players Location: 0x55555d3a34c0 Posted at: 2018-05-03, 18:48 Experimented some more and it turned out that actually the error message is incorrect. It´s `luaL_checkstring()` that can´t cope with integer keys for whatever reason, not `lua_next()`. Checking for `lua_type(L, -1)` fixes that problem. I guess you'd have to iterate over the current table to check if all keys can be reverted to consecutive ints, starting from 1. As far as I know, tables can either be arrays with indices 1..n, or have only strings as keys. I now implemented a solution where integer keys are ignored when saving; and entries with no keys defined are assigned to an integer key when reading. If my guess is incorrect, this design is fragile though… Finally, one small bug remaining: In arrays, `nil` values are silently omitted while saving; so any indices after `nil` values are decremented in reading the data. Example: ``````game:save_campaign_data("test_campaign", "test_scenario", { "Hello", nil, "World" -- index of "World" is 3 } local data = game:read_campaign_data("test_campaign", "test_scenario") --> data = {"Hello", "World"} -- index of "World" is 2 `````` I have no idea where this could come from… Top Quote GunChleoc Joined: 2013-10-07, 15:56 Posts: 3159 One Elder of Players Location: RenderedRect Posted at: 2018-05-03, 21:42 You could check for nil values when saving and trigger report_error if there are any. If somebody is saving nil values, chances are good that there is something wrong with the data being saved anyway. Busy indexing nil values Top Quote Nordfriese Joined: 2017-01-17, 18:07 Posts: 699 One Elder of Players Location: 0x55555d3a34c0 Posted at: 2018-05-04, 09:37 But if a `nil` value exists, the mandatory typecheck should return neither `"string"`, `"number"`, `"boolean"` nor `"table"`, so the `if/else` block would already trigger an error, just like it does when an object is used as a value. Perhaps this is the fault of `lua_next()`, it appears to skip keys that are mapped to `nil`. I don´t know why it confuses the int-keys then, though. I wrote a warning for this bug in the documentation of `save_campaign_data()`, perhaps we could leave it as it is? Top Quote GunChleoc Joined: 2013-10-07, 15:56 Posts: 3159 One Elder of Players Location: RenderedRect Posted at: 2018-05-04, 16:57 I'll have to take a look at the code. Please ping me if you don't hear from me by Monday. Busy indexing nil values Top Quote