Page 1 of 1

How can I make my code better ? [solved]

Posted: Fri Feb 10, 2023 4:45 am
by zalander
I wrote some code for loading and saving a file, I was just thinking how can I make it better

Code: Select all

l = {}
function l.load()
    if love.filesystem.getInfo("score.lua") then
        return(love.filesystem.read("score.lua"))
    else
        love.filesystem.newFile("score.lua")
        love.filesystem.write("score.lua", 0)
        return(love.filesystem.read("score.lua"))
    end
end
function l.save(val)
    love.filesystem.write("score.lua", val)
end
Hope you guys will help !
:awesome:

Re: How can I make my code better ?

Posted: Fri Feb 10, 2023 6:05 am
by darkfrei
First writing must be in saving, but you can have the same default file in the game, it will be loaded instead of not yet created.

Re: How can I make my code better ?

Posted: Fri Feb 10, 2023 4:24 pm
by fridays18
zalander wrote: Fri Feb 10, 2023 4:45 am I wrote some code for loading and saving a file, I was just thinking how can I make it better

Code: Select all

l = {}
function l.load()
    if love.filesystem.getInfo("score.lua") then
        return(love.filesystem.read("score.lua"))
    else
        love.filesystem.newFile("score.lua")
        love.filesystem.write("score.lua", 0)
        return(love.filesystem.read("score.lua"))
    end
end
function l.save(val)
    love.filesystem.write("score.lua", val)
end
Hope you guys will help !
:awesome:
Giant forum about all the different ways to save and load with a bunch of different methods viewtopic.php?f=3&t=94262

Re: How can I make my code better ?

Posted: Fri Feb 10, 2023 6:39 pm
by Andlac028
zalander wrote: Fri Feb 10, 2023 4:45 am I wrote some code for loading and saving a file, I was just thinking how can I make it better

Code: Select all

l = {}
function l.load()
    if love.filesystem.getInfo("score.lua") then
        return(love.filesystem.read("score.lua"))
    else
        love.filesystem.newFile("score.lua")
        love.filesystem.write("score.lua", 0)
        return(love.filesystem.read("score.lua"))
    end
end
function l.save(val)
    love.filesystem.write("score.lua", val)
end
Hope you guys will help !
:awesome:
Do not name file score.lua, of it does not contain lua code, name it .txt, .score, .anything, but .lua is saying like it has some code inside, which it don’t have.

Also it is okay to store one value in a file, but if you want to add something else, but it everything in one file, do not have many files (maybe if you have a lot of different data, divide it to some files, if you want to load only some data at time). And if you have to save a lot of data, use some serializer library (or for smaller games, I think love.data.pack and love.data.unpack is enought) to make your life easier. And in that case, please save only data, that are really needed to be saved, or data, that are difficult to compute.

It is useless to create file with default value, if it doesn’t exist, just return default value and save only when you have some real value to save.

Just side note, please do not use save and load in frequwnt way, as it may slow down game and wear out disk. It is ok to save every, lets say, 5 or 10 minutes, but do not save it very frequently. Also you may cinsider saving on quit, or on error, or in some fixed interval, or after bigger progress.

Just small note, you can also love.filesystem.exists() as it is faster and does not create unnecesarry table, if you need to check for a lot of files. Yes, it is deprecated, but if I remember correctly, it is readded in development version.

Re: How can I make my code better ?

Posted: Sat Feb 11, 2023 6:11 am
by ivan
Your function called "load" uses love.filesystem.newFile and love.filesystem.write.
This does not make sense because the function is called "load", but you are writing to the disk in the same function.
Furthermore you do not want to hard-code filenames like "score.lua".

Re: How can I make my code better ?

Posted: Sat Feb 11, 2023 8:45 am
by soulmata
For player data vs game data, it's important to note that LOVE itself has only a single location it can read and write to. If you need to load data not in a LUA module from the game directory for editing (for instance, a map editor), you'll need to write your own functions using LUA's file system libraries. This is not much more difficult to do than using LOVE, but you have to be more careful, as you're reading/writing to a location that you may not have write access to.

A typical game is likely going to need at least 2 files: a profile for the user, and their savegame data, assuming you persist state. Note that persisting state itself can be very tricky, depending on the method you use. I use the commonly-available "persistence" module, but also go to great lengths to ensure I'm not using upvalues (you generally CANNOT persist upvalues to a file), as well as trawl the data to ensure I'm not writing data that is identical to a vanilla game state.

It's also important to ensure you are guarding against failures, since the file might not be there, might not be writeable, might have invalid data, et cetera. So what I do is pack a read function with a separate validation function that is ensuring 1) I'm only reading the data I expect to be in there 2) That data conforms to a particular type. Here's an example from a game I have in development:

Code: Select all

  -- load saved profile if it exists
  love.filesystem.setIdentity( "EndlessDark", false )
  local loadprofile = false -- default to doing nothing
  local f = "profile.txt"
  local d = love.filesystem.getSaveDirectory()
  if (d) then
    local file
    local errstr
    local s
    local err
    local pf = d .. "/" .. f
    f_ed_log("SYSTEM: Determined profile path to be " .. d .. "/" .. f, "debug")
    local pft = love.filesystem.getInfo( f )
    if (pft) then
      f_ed_log("SYSTEM: Profile " .. pf .. " exists, attempting to load.", "debug")
      local load = f_ed_load_profile(f)
    else
      f_ed_log("SYSTEM: Profile " .. pf .. " does not exist, attempting to create.", "debug")
      local made = f_ed_create_profile(f)
      if (made) then
        f_ed_log("SYSTEM: Profile " .. pf .. " has been created.", "debug")
      else
        f_ed_log("SYSTEM: Profile " .. pf .. " could not be created.", "debug")
      end
    end
  else
    f_ed_log("SYSTEM: Failed to determine save directory, cannot load profile.txt", "debug")
  end
There are many reasons those things COULD fail, so make sure you guard against that. Then after all of that, for every key I am going to read OR write from that file, I individually vet it - there's one function to validate strings, and another to validate bools, and in both cases there's an extra step to ensure the loaded value matches the ranges I require, otherwise it's discarded and a new profile value written.

Code: Select all

function f_ed_validate_profile_key_as_string_to_num(id)
  if not(id) then return false end
  if not(type(id) == "string") then return false end

  -- list of profile keys we take as strings and convert to a number
  local t = {
    memory_core_stage    = true,
    num_victory_annie    = true,
    num_victory_robbie   = true,
    num_victory_frank    = true,
    num_attempt_annie    = true,
    num_attempt_robbie   = true,
    num_attempt_frank    = true,
    stress_breaks_annie  = true,
    stress_breaks_robbie = true,
    stress_breaks_frank  = true,
    went_crazy_annie     = true,
    went_crazy_robbie    = true,
    went_crazy_frank     = true,
    winstreak_total      = true,
    repairs_total        = true,
    sabotage_total       = true,
    npcs_died_annie      = true,
    npcs_died_robbie     = true,
    npcs_died_frank      = true,
    musicvol             = true,
  }

  if (t[id]) then return true else return false end

Re: How can I make my code better ?

Posted: Sat Feb 11, 2023 12:33 pm
by zalander
Thanks for the help guys I figured it out !