ID:2170630
 
(See the best response by Nadrew.)
Problem description:
I'm trying to save some of the world related info into a savefile, it seems to save fine, but when I'm trying to load it, it doesn't load correctly.

Code:
proc
SaveWorldData()
var/savefile/F = new/savefile("world.sav")
F["time"] << time
F["time"] << day
F["time"] << month
F["time"] << year
F["time"] << timeOfDay
world.log << time
world.log << day
world << System() + "World data saved successfully"

//Loads information relevant to the world
LoadWorldData()
var/fname = "world.sav"
if(fexists(fname))
var/savefile/F = new/savefile(fname)
F["time"] >> time
F["time"] >> day
F["time"] >> month
F["time"] >> year
F["time"] >> timeOfDay
world.log << time
world.log << day
world << System() + "World data loaded successfully"

Aurimas33 wrote:
Problem description:
I'm trying to save some of the world related info into a savefile, it seems to save fine, but when I'm trying to load it, it doesn't load correctly.

Code:
> proc
> SaveWorldData()
> var/savefile/F = new/savefile("world.sav")
> F["time"] << time
> F["time"] << day
> F["time"] << month
> F["time"] << year
> F["time"] << timeOfDay
> world.log << time
> world.log << day
> world << System() + "World data saved successfully"
>
> //Loads information relevant to the world
> LoadWorldData()
> var/fname = "world.sav"
> if(fexists(fname))
> var/savefile/F = new/savefile(fname)
> F["time"] >> time
> F["time"] >> day
> F["time"] >> month
> F["time"] >> year
> F["time"] >> timeOfDay
> world.log << time
> world.log << day
> world << System() + "World data loaded successfully"
>


Try


//Save:
F["time"] << time
F["day"] << day
F["month"] << month

//Load:
F["time"] >> time
F["day"] >> day
F["month"] >> month

Everywhere you use the same type: F["time"]
Best response
Right, you're basically overwriting it each time, think of savefiles like a file structure, they have directories and files that contain data.

var/savefile/F = new("mysave.sav")

F.dir = "my_data"
F["one"] << 1
F["two"] << 2
F["three"] << 3
F.cd = "../other_data"
F["one"] << 2
F["two"] << 1
F["three"] << "taco"


That'll generate a savefile looking something like:
my_data
"one" = 1
"two" = 2
"three" = 3

other_data
"one" = 2
"two" = 1
"three" = "taco"


You can navigate around the saves like you would a data system using savefile.cd (and related savefile variables like savefile.dir), and for accessing the data you have a few options.

var/savefile/F = new("mysave.sav")

F["my_data/three"] >> variable // 3
var/other_data_three >> variable // "taco"


Or

var/savefile/F = new("mysave.sav")
F.cd = "my_data"
F["three"] >> variable // 3
F.cd = "../other_data"
F["three"] >> variable // "taco"


Savefiles have special handling for saving things like datums (all of them, including players, clients, objects, whatever) which will automatically save all of the non-tmp, non-const variables that have been changed from their initial value in the same structure I mentioned above (in a more complex format of course, you can check out savefile contents by using ExportText()). Lists and icons are also stored in their own ways, but storing icons is generally a bad idea because it leads to a lot of file bloat (especially when you have an inventory full of items with dynamic icons that all get saved with their icon data and whoaaaa massive files).

You can handle the process by overriding atom.Read() and atom.Write() to catch and filter data if needed.

var/savefile/player_save = new("players/[src.ckey].sav")
player_save["player"] << src


This will save the player and most of its related variables, minus stuff like location data.

var/savefile/player_save = new("players/[src.ckey].sav")
player_save["player"] >> player_mob
client.mob = player_mob


For loading it.

You need to be careful about saving variables that are references as well because it will save the object in the state it's in at that time, which is great for inventories and things of that nature, but if you have say, a variable that references another player that's not a tmp variable it'll be saved, saving that other player in the state they're in at that time.

So what happens to that player if they're happily chugging along when a person who happened to save a reference to them a week ago logs back in after taking a break? Well crap, that old reference to that person just got loaded because the other person's savefile had a full save of them. This is known as the "rollback effect" which many games have fallen into by not keeping track of variables that should and shouldn't be saved.

If you have a variable that references anything that's not directly belonging to that thing, it should be tmp, if you need to keep track of said thing between loads, you should save some kind of text reference to it, like an id or tag.
Thanks a lot, I've managed to fix it with your help!

    //Saves information relevant to the world to a file
SaveWorldData()
var/savefile/F = new/savefile("world.sav")
F["time/time"] << time
F["time/day"] << day
F["time/month"] << month
F["time/year"] << year
F["time/timeOfDay"] << timeOfDay
world << System() + "World data saved successfully"

//Loads information relevant to the world
LoadWorldData()
var/fname = "world.sav"
if(fexists(fname))
var/savefile/F = new/savefile(fname)
F["time/time"] >> time
F["time/day"] >> day
F["time/month"] >> month
F["time/year"] >> year
F["time/timeOfDay"] >> timeOfDay
world << System() + "World data loaded successfully"
That looks pretty solid, but I'm super curious what System() does, I have a feeling it might be one of those things a #define might handle with less overhead.
You were right, and I'm now switching that one out too, thanks for noticing and reminding me. Haven't coded byond for a rather long time now. But is there a way to make the #define global, doing it for every single file where it's used seems rather tedious
In response to Aurimas33
#define affects all code compiled after it. If you put them in a file that is included first, like "__defines.dm" or the .dme itself, it'll be seen in all code files.
To save yourself a little hassle and also make the saving/loading easier, I suggest this:

//Saves information relevant to the world to a file
SaveWorldData()
var/savefile/F = new/savefile("world.sav")
F.cd = "time"
F["time"] << time
F["day"] << day
F["month"] << month
F["year"] << year
F["timeOfDay"] << timeOfDay
world << System() + "World data saved successfully"

//Loads information relevant to the world
LoadWorldData()
var/fname = "world.sav"
if(fexists(fname))
var/savefile/F = new/savefile(fname)
F.cd = "time"
F["time"] >> time
F["day"] >> day
F["month"] >> month
F["year"] >> year
F["timeOfDay"] >> timeOfDay
world << System() + "World data loaded successfully"