Saving / Loading to / from a file

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Pratix
Prole
Posts: 5
Joined: Sat Feb 04, 2023 11:46 pm

Saving / Loading to / from a file

Post by Pratix »

Hello! I'm new to using love and I am curious on how to make a save / load system for my game. The player can edit the level in-game but I want to get it to save to a file where when the game is reopened the level is regenerated as after it was edited (for example, the level is completely blank but I place a gold block, and then close and reopen the game the golden block will still be there) If anyone knows the solution I would deeply appreciate it, thank you!
User avatar
knorke
Party member
Posts: 274
Joined: Wed Jul 14, 2010 7:06 pm
Contact:

Re: Saving / Loading to / from a file

Post by knorke »

There is currently an active thread about reading/writing files:
viewtopic.php?f=3&t=94262
Read all posts, there are different approaches.

What is best depends on your game. Is it tile-based?
MrFariator
Party member
Posts: 559
Joined: Wed Oct 05, 2016 11:53 am

Re: Saving / Loading to / from a file

Post by MrFariator »

More or less, you save the necessary information about the game level via in its present state with love.filesystem.write, which will write a file to your game's save folder (location is OS dependent; see this page). However, you can't directly just take a typical lua table and save it with the afore-mentioned function, and instead need to serialize the level data somehow. Essentially, turning the lua table into a binary or string representation, that can be written into a file, and then read back to reconstruct the original table contents. To this end, there are many serialization libraries out there to use, each with their pros and cons - so pick the one you like the most. Personally, I use bitser.

After you've saved the file, you then simply load the file with something like love.filesystem.read, and then deserialize the contents (ie. reverse the serialization process, with the library you chose or otherwise).

This is basically the gist of the whole process, for everything from saving a level, to a more mundane save system that only tracks a few variables.
Pratix
Prole
Posts: 5
Joined: Sat Feb 04, 2023 11:46 pm

Re: Saving / Loading to / from a file

Post by Pratix »

MrFariator wrote: Sun Feb 05, 2023 12:44 am More or less, you save the necessary information about the game level via in its present state with love.filesystem.write, which will write a file to your game's save folder (location is OS dependent; see this page). However, you can't directly just take a typical lua table and save it with the afore-mentioned function, and instead need to serialize the level data somehow. Essentially, turning the lua table into a binary or string representation, that can be written into a file, and then read back to reconstruct the original table contents. To this end, there are many serialization libraries out there to use, each with their pros and cons - so pick the one you like the most. Personally, I use bitser.

After you've saved the file, you then simply load the file with something like love.filesystem.read, and then deserialize the contents (ie. reverse the serialization process, with the library you chose or otherwise).

This is basically the gist of the whole process, for everything from saving a level, to a more mundane save system that only tracks a few variables.
I actually decided to search up how to read / write to file in lua and found io.open()

Basically it opens a file for read / write or whatever you want and you can then write / read to / from file and close it and for me it works! So I highly appreciate the help but for me i am going to simply use io.open() as it is much simpler for me. Thank you though!
User avatar
BrotSagtMist
Party member
Posts: 659
Joined: Fri Aug 06, 2021 10:30 pm

Re: Saving / Loading to / from a file

Post by BrotSagtMist »

Please do not use io.open stuff in löve.
This is NOT compatible with other users, basically your program will only work for yourself then.
obey
Pratix
Prole
Posts: 5
Joined: Sat Feb 04, 2023 11:46 pm

Re: Saving / Loading to / from a file

Post by Pratix »

BrotSagtMist wrote: Sun Feb 05, 2023 1:15 am Please do not use io.open stuff in löve.
This is NOT compatible with other users, basically your program will only work for yourself then.
Why is this? I don't see a compatibility issue, could you further explain?
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: Saving / Loading to / from a file

Post by Bigfoot71 »

If it can help you to write yours here is the first of my many backup scripts that I could write, it is far from being the most perfect (the first) but it is quick to use and quite easy to understand by compared to the others that I could have proposed:

Code: Select all

require("lib/TSerial")

local SM = {}

function SM.getDataTable(data)
    if type(data) ~= "table" then
        error("SM.getDataTable only takes a table as a parameter.")
    else
        SM.data = data
    end
end

function SM.getSaveName(name)
    if type(name) ~= "string" then
        error("SM.getSaveName only takes a string as a parameter.")
    else
        SM.name = name
    end
end

function SM.save(data, name)

    if type(data) ~= "table" then
        if type(SM.data) == "table" then
            data = SM.data else return false
        end
    end

    if type(name) ~= "string" then
        if not SM.name then
            error("SM.save has no name given as a parameter nor previously saved.")
        else
            name = SM.name
        end
    end

    local temp = TSerial.pack(data)

    temp = love.data.compress("string", "zlib", temp, 9)
    temp = love.data.encode("string", "base64", temp)

    love.filesystem.write(name, temp)

    return true

end

function SM.load(name)

    if type(name) ~= "string" then
        if not SM.name then
            error("SM.save has no name given as a parameter nor previously saved.")
        else
            name = SM.name
        end
    end

    local data

    if love.filesystem.getInfo(name) then
        data = love.data.decode("string", "base64", love.filesystem.read(name))
        data = love.data.decompress("string", "zlib", data)
        data = TSerial.unpack(data)
    else
        return false
    end

    if SM.data then

        for i,v in pairs(data) do
            SM.data[i] = v
        end

        return true

    end

    return data

end

return SM
It was before I wrote my own serialization script so it uses TSerial, to use it is really not a headache, you make a model of your save:

Code: Select all

Save = { score = 0 }
Then if you are only supposed to have one backup you can do:

Code: Select all

SaveMan.getDataTable(Save)
SaveMan.getSaveName("save.dat")
This way you won't need to fill in the `save()` and `load()` parameters anymore, although you can still do it even afterwards. And you can load directly in stride, the table will not be modified if there is no save to load:
SaveMan.load()

And to save you only have to do:

Code: Select all

SaveMan.save()
The scripts uses Löve's functions to compress and encode the backup, which makes it less easily editable for cheats, there are of course other ways to optimize this.

I share this one with you as an example because I know that it is largely optimizable but offers a good idea of ​​what it could look like, so I encourage you to write yours with your own features! ^^

Otherwise for using the Lua I/O module this may not work for all users as it depends on the operating system and file access permissions. Löve you have already "chewed" the work on this question for not going into details,
My avatar code for the curious :D V1, V2, V3.
Pratix
Prole
Posts: 5
Joined: Sat Feb 04, 2023 11:46 pm

Re: Saving / Loading to / from a file

Post by Pratix »

Alright, thanks for the explanation. This will really help with my game as I really needed this saving code. Thank you!
User avatar
BrotSagtMist
Party member
Posts: 659
Joined: Fri Aug 06, 2021 10:30 pm

Re: Saving / Loading to / from a file

Post by BrotSagtMist »

Pratix wrote: Sun Feb 05, 2023 1:16 am
BrotSagtMist wrote: Sun Feb 05, 2023 1:15 am Please do not use io.open stuff in löve.
This is NOT compatible with other users, basically your program will only work for yourself then.
Why is this? I don't see a compatibility issue, could you further explain?
Cause this is absolute file system access.
It requires every user to have the exact same hardrive setup as you. And even then it will break on different OS.
Thats why löve provides its own read and write which abstracts access to a _fitting_ place depending on what system the user uses.
obey
MrFariator
Party member
Posts: 559
Joined: Wed Oct 05, 2016 11:53 am

Re: Saving / Loading to / from a file

Post by MrFariator »

Putting aside any file access, file locations or other issues with io.open, another issue is how the io library can often silently fail when dealing with large chunks of data, files containing utf8 strings, and other subtler issues. The issues got to a point that when I wanted to save to a location outside of LÖVE's save folder (for some debug/development purposes; nothing I'd put in a released game), I used love.filesystem.write to write a file to save folder, and then copy that file by executing an OS-dependent file copying command with lua's os.execute. Sounds very roundabout way of doing things, but it worked far better than any of the io.* functions.

To put it short, LÖVE's file system functions are far more robust (outside restricting you into saving files to the save folder; which is what you likely want to do anyway), and less error-prone. Use them to save a bit of your sanity.
Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests