Solarus-Games English Forum

Solarus => Development => Topic started by: MetalZelda on March 10, 2017, 05:42:24 PM

Title: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 10, 2017, 05:42:24 PM
Greetings.

Recently i've been working on the final title screen based on RPG / Zelda BOTW.
And so comes this idea of unlimited saves number.

(http://i.imgur.com/2gQpdsg.png)

however, i wanna display all files stats here, i already know how to do it, the problem is, the menu is a scroll type menu, with as max_position, the number of saves, however, I can't figure out how to count how many files with "save" prefix exists, if anyone have a clue, i'll gladly take it
Title: Re: Count how many file exists with a certain prefix ?
Post by: Christopho on March 10, 2017, 08:50:25 PM
You have to test them one by one in a loop, there is no way to get all files from a folder (yet).
Title: Re: Count how many file exists with a certain prefix ?
Post by: wizard_wizzle (aka ZeldaHistorian) on March 10, 2017, 10:11:40 PM
You can use a break statement in Lua, so it should be pretty easy to accomplish (as long as they're named sequentially).
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 11, 2017, 01:03:35 AM
Okay I've been able to make it work, however, sol.game.load is slow when dealing with a lot of files, yet, there is no huge ressource consumption, whick makes the slowdown weird, so I'm limitting the files to 4

(http://i.imgur.com/10npTXF.png)

Thanks
Title: Re: Count how many file exists with a certain prefix ?
Post by: Christopho on March 11, 2017, 01:19:00 AM
Don't try to sol.load() all potential files, just test if they exist. With sol.file.exists().
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 11, 2017, 12:41:38 PM
Quote from: Christopho on March 11, 2017, 01:19:00 AM
Don't try to sol.load() all potential files, just test if they exist. With sol.file.exists().

Yes, I know this, this is how i is done currenly, but if all of them exists, we need to load them all, which cause freeze sometimes. Strangely, loading all files only takes around a megabyte on the ram, so this is weird
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 12, 2017, 10:11:50 PM
I mean, to display infos of a certain file, you need to sol.game.load, and this is why there are some freezes
Title: Re: Count how many file exists with a certain prefix ?
Post by: YoshiMario2000 on March 12, 2017, 10:35:00 PM
Well, my advice is to only load the visible files in the menu when required to show them (i.e. a scrolling menu where only three are shown at a time.), store the variable that you need into a list with in a list (arrays work too). This should spread out the load time to when the user attempts to access the other files additional files. Also, you should probably make it so that it sorts by most recently saved. Most users are not going to touch their old saves unless they want to show off their progress or just mess with it.

You could also attempt to use
Code ( lua) Select
local game_var = require("path/to/save/data.dat")
But don't know if that will work.
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 13, 2017, 11:34:16 AM
Quote from: YoshiMario2000 on March 12, 2017, 10:35:00 PM
Well, my advice is to only load the visible files in the menu when required to show them (i.e. a scrolling menu where only three are shown at a time.), store the variable that you need into a list with in a list (arrays work too). This should spread out the load time to when the user attempts to access the other files additional files. Also, you should probably make it so that it sorts by most recently saved. Most users are not going to touch their old saves unless they want to show off their progress or just mess with it.

You could also attempt to use
Code ( lua) Select
local game_var = require("path/to/save/data.dat")
But don't know if that will work.

The first idea is a good solution, only loading 2 files (the visible ones) is a rather cool solution, gonna try what I can get with this solution, and sorting by the most recent save is a rather good solution, but, it might be complex to do, I mean the table containing saves need to be arranged with one parameter, the most recent file, don't know if Lua have this or if it might work with all OS.

One solution here
http://stackoverflow.com/questions/33470835/get-file-creation-time-with-lua
One other here
http://stackoverflow.com/questions/33296834/how-can-i-get-last-modified-timestamp-in-lua

At least, the menu is nearly done, so this might be not so long
https://www.youtube.com/watch?v=goCbfhRsnOY

And, one save = 1 quest save, so this helps not dealing with a lot of saves, i should re-implement file copying, there is already something that analyse if 1 file doesn't exist so it will be the first file to be created
Title: Re: Count how many file exists with a certain prefix ?
Post by: Christopho on March 13, 2017, 11:51:10 AM
The idea of loading files lazily (only when the info is needed to be displayed) is great!

About the second suggestion with require, forget about it. require() is meant to include other scripts, not data files. It would not work since savegames are data files that don't return anything. You would not be able to read any result. And even if you could, it would be wrong because savegame files can have changed in the meantime if the user has played a while, has saved, and then went back to the savegame menu. Remember that require() only loads the script file the first time and keep its result in cache.
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 13, 2017, 12:08:51 PM
Quote from: Christopho on March 13, 2017, 11:51:10 AM
The idea of loading files lazily (only when the info is needed to be displayed) is great!

About the second suggestion with require, forget about it. require() is meant to include other scripts, not data files. It would not work since savegames are data files that don't return anything. You would not be able to read any result. And even if you could, it would be wrong because savegame files can have changed in the meantime if the user has played a while, has saved, and then went back to the savegame menu. Remember that require() only loads the script file the first time and keep its result in cache.

Yes that's a cool idea, it could break the freeze when loading a lot of savegames, yet, I am liking YoshiMario2000's idea of sorting the save menu by the most recently played game, the code already organize saves so, even if save 3 is missing but save 4 exists, it'll be correctly display save 4 in the GUI's slot 3, is there a simpler way than the links i've poster above to organize the array by the last modified file ?
Title: Re: Count how many file exists with a certain prefix ?
Post by: llamazing on March 13, 2017, 02:30:55 PM
Am I correct in assuming that the only reason you are "loading" the savegame files is to get access to the state of the savegame variables?

If so, perhaps what is needed is some sort of quick load feature that only gives read access to savegame variables but doesn't do any of the other loading of resources needed to actually start the game and therefor would be faster for checking multiple files.
Title: Re: Count how many file exists with a certain prefix ?
Post by: Christopho on March 13, 2017, 02:32:17 PM
With sol.main.load_file (and not require!) and setfenv it is possible.
Or sol.file.open and parsing the file by hand, because setfenv no longer exists in Lua 5.2 (replaced by ENV_) so you will have a problem if one day we change the Lua version.
Title: Re: Count how many file exists with a certain prefix ?
Post by: Diarandor on March 13, 2017, 02:51:57 PM
Another solution is to save in a common different file the savegames info that you need to show, so you can load it fast. You can override the saving function "game:save()", so that this info is saved in that other file. Maybe a new instance of "game" can be used to save this in the new file, without starting that game.
Title: Re: Count how many file exists with a certain prefix ?
Post by: Christopho on March 13, 2017, 03:20:46 PM
Good idea! Since you can create any file, you can create one that maintains the list of savegames. Simple as that.

But don't overwrite game:save(), just create your own function (in game_manager or whatever) that calls game:save() and updates the file. It is best practice not to change the official API when it is not necessary.
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 13, 2017, 04:54:29 PM
Yeah i'm completely right with Diarandor's solution, yet, something is unclear because you need to open the concerned save to get the value and write it to another file, maybe using Chris's solution will work, allowing unlimited saves

That also get me to the point where input customisation need to be stored in a file so we can bind custom inputs, even if we are not in a game, but that's something else.
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 14, 2017, 11:28:42 AM
I find a solution, but, I'm unable to extract the needed values in order to insert them in a table, io.lines(file) always return an error. (bad argument #1 to 'lines' (string expected, got userdata))

EDIT: it works, but now how can I extract the value I need from this certain file ?

Doing through setfenv, don't know if that's the right way

Code (lua) Select
function title_screen:do_file(i, name)
  local slot = self.slots[i]
 
  local environment = {
    prop = function()
  slot.max_health = _max_life,
  slot.current_health = _current_life
  slot.player_name = player_name
  slot.tunic = _ability_tunic
  slot.shield = _ability_shield
  slot.sword = _ability_sword
end,
  }
 
  setmetatable(environment, {
    __index = function()
      return function() end
    end
  })
 
  local chunk = sol.main.load_file(name)
  setfenv(chunk, environment)
  chunk()
end
Title: Re: Count how many file exists with a certain prefix ?
Post by: Christopho on March 14, 2017, 02:04:44 PM
Just use file:lines() instead of io.lines(). io.lines takes a filename, not a file.

setfenv also works (parsing the data file as Lua) but I don't like it so much because it is a function that no longer exists in Lua 5.2. If we switch to a newer Lua version than 5.1 one day, there will be a compatibility issue. Not a big deal, because Lua 5.2 introduces a new (and better) way, but still some manual changes required.
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 14, 2017, 06:04:08 PM
I finally got the file to load and store values in a array, things like hearts display need to be done completely manually.

Thanks for the help
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 14, 2017, 07:41:49 PM
Is it possible to arrange an array in order to display at first the last game played, the modification date of the file might be enough but is it possible through lua ?
100 saves slots should be enough, there are no more lags whe loading all files

Edit: restict to 90 saves, above 90 saves (90 * 90), the surface won't even draw, don't know if it's a bug when a surface above 8100 pixels won't draw
Title: Re: Count how many file exists with a certain prefix ?
Post by: Diarandor on March 14, 2017, 11:11:05 PM
I think 20 or 30 savegames is more than enough. In order to get first the last game played, I think the easiest solution is to save another variable with the index of the last savegame. Each time you save a game you should update the file with your savegame menu info (I think that is what you are already doing, but I am not sure), and at that time you can save this index too.
Title: Re: Count how many file exists with a certain prefix ?
Post by: llamazing on March 14, 2017, 11:16:35 PM
You can use a custom sort function to arrange things however you want. The following example assumes that the date is some number that increases over time.

Code (lua) Select
local function sort_by_date(a, b)
return a.date > b.date --descending order
--return a.date < b.date --ascending order
end

local example_data = {
{ date = 56, name = "second" },
{ date = 99, name = "first" },
{ date = 21, name = "third" },
}

print"Original Order:"
for i,data in ipairs(example_data) do
print(string.format("%i - date: %f, name: %s", i, data.date or 0, data.name))
end

table.sort(example_data, sort_by_date)

print"\nSorted by Date:"
for i,data in ipairs(example_data) do
print(string.format("%i - date: %f, name: %s", i, data.date or 0, data.name))
end
Title: Re: Count how many file exists with a certain prefix ?
Post by: MetalZelda on March 15, 2017, 12:04:56 PM
Quote from: llamazing on March 14, 2017, 11:16:35 PM
You can use a custom sort function to arrange things however you want. The following example assumes that the date is some number that increases over time.

Code (lua) Select
local function sort_by_date(a, b)
return a.date > b.date --descending order
--return a.date < b.date --ascending order
end

local example_data = {
{ date = 56, name = "second" },
{ date = 99, name = "first" },
{ date = 21, name = "third" },
}

print"Original Order:"
for i,data in ipairs(example_data) do
print(string.format("%i - date: %f, name: %s", i, data.date or 0, data.name))
end

table.sort(example_data, sort_by_date)

print"\nSorted by Date:"
for i,data in ipairs(example_data) do
print(string.format("%i - date: %f, name: %s", i, data.date or 0, data.name))
end


This might be the only solution, yet, the only parameter needed here is the file's last modifcation date which will be stored in file.date, then this will be fairly possible with your function

This is how infos are retrieved from a savegame file

Code (lua) Select
function title_screen:do_file(i, name)
  local file = sol.file.open(name)
  local slot = { dungeon = {} }

  -- This should be where the last modification date will be stored
  -- slot.date = ???
 
  local font, font_size = sol.language.get_dialog_font()
  slot.player_name_text = sol.text_surface.create{
    font = font,
    font_size = font_size,
  }
 
  for line in chunk:lines() do
    -- Player stats
    if line:match("player_name")then
  slot.player_name_text:set_text(line:sub(16, -2))
end
if line:match("_ability_shield") then
  slot.shield = line:sub(19)
end
if line:match("_ability_sword") then
  slot.sword = line:sub(18)
end
if line:match("_ability_tunic") then
  slot.tunic = line:sub(18)
end
-- Game stats
if line:match("_current_life") then
  slot.current_life = line:sub(17)
end
if line:match("_max_life") then
  slot.max_life = line:sub(13)
end
if line:match("hero_mode") then
  slot.hero_mode = line:sub(13)
end
if line:match("finished_game") then
  slot.finished_game = line:sub(17)
end

-- Dungeon state
if line:match("dungeon_1_finished") then
  slot.dungeon[1] = true
end
       -- blablabla
  end
 
  file:close()
  slot.savegame_number = i
  self.slots[i] = slot
end


The file organisation is done somewhere else when another function, more explainatory, is called, here, i just want the last modification date
Title: Re: Count how many file exists with a certain prefix ?
Post by: Christopho on March 15, 2017, 01:44:55 PM
There is probably a shorter way to parse the savegame files. Here is an example of the string.gmatch (https://www.lua.org/manual/5.1/manual.html#pdf-string.gmatch) official doc:
Code (lua) Select

-- The next example collects all pairs key=value from the given string into a table:
     t = {}
     s = "from=world, to=Lua"
     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
       t[k] = v
     end

This example can be adapted to include string values (enclosed inside double quotes) and it should just work.