Godot Version
4.3 stable
Question
I have a setup where i save through writing into a cfg file. Stupid probably, but I cant see if dict saving would be different. Maybe someone can elaborate on how to do this feasibly?
.
I start by this:
var health
#imagine having 200 vars here
.
to save i do this:
var savefile = ConfigFile.new()
savefile.set_value("data","health", health)
#imagine having 200 vars here
savefile.save(savefile_main)
.
to load i do this:
var savefile = ConfigFile.new()
savefile.load(savefile_main)
health = savefile.get_value("data","health",100.0)
#imagine having 200 vars here
.
ok, imagine having 200 vars to saveâŚ
I end up writing names of variables many many times. I wish i could do it in a way where i only had to sort of register an item once, and then i could iterate over the items when i save the whole bunch, when i load the whole bunch,
if only it was sane to do a str_to_var thing (which i know it isnt!)
anyone has some inputs on this?
1 Like
im not quite sure what exactly you want, but have you looked at the ResourceSaver? It allows you to saves resources, which can contain hundreds of variables, easily
1 Like
Just save them into Dictionary, like this:
# The dictionary syntax itself if you never used one:
var game_data = {
"health": 100.0,
"mana": 50.0,
"level": 1,
"position": Vector2(120,20)
# ... more variables
}
# Saving
func save_game():
var savefile = ConfigFile.new()
for key in game_data.keys():
savefile.set_value("data", key, game_data[key])
savefile.save(savefile_main)
1 Like
If you really do have a great number of class-body variables you can use get
and set
along with an array of strings denoting which variables to save. Though this doesnât leave much room for failure conditions.
const TO_SAVE = [
"health", "money", "coins",
"copper", "gold", "dabloons",
"cash", "dollars", "gp",
]
func save() -> void:
var savefile = ConfigFile.new()
for var_name in TO_SAVE:
savefile.set_value("data", var_name, get(var_name))
savefile.save(savefile_main)
func load() -> void:
var savefile = ConfigFile.new()
savefile.load(savefile_main)
for var_name in TO_SAVE:
set(var_name, savefile.get_value("data", var_name)
1 Like
Like @herrspaten suggested, use resources and save with ResourceSaver.save()
.
Thereâs reasons to not use resources for data serialization, such as for networked games and shareable assets where it could open up a remote code execution vulnerability. Otherwise, use custom resources. They are great.
Example:
class_name YourData extends Resource
@export var health = 0xDEAD
@export var max_stamina = 100
# ---
# Some other place:
const data_path = "user://your_data.tres"
var your_data
func load_data():
if ResourceLoader.exists(data_path):
your_data = load(data_path)
else:
your_data = YourData.new()
func save_data():
assert(your_data != null)
ResourceSaver.save(your_data, data_path)
Alternative
A more advanced alternative is to use get_property_list()
. Filter out your script properties. Serialize those properties to config file, json, etc. And then the inverse.
1 Like
thanks i will read into this. Iâm not fully equipped to wrap my head around this
thanks alot. i will read into these things a bit.
in this case how would i then, ie, get how many, say, âcoinsâ i have?
just inventing a strange example here:
A char says âi see you have x coinsâ
I want that char to then look up the value of the âcoinâ entry in the save data.
How would i do that?
To access the data in a dictionary you simply do this:
game_data["health"]
So for the example you used:
func check_coins(game_data: Dictionary):
print("You have %d coins." % game_data["coins"])
Of course, in a real game scenario to not risk crashes, I would employ a safe way to check if the key exists to grab errors, like here:
func check_coins(game_data: Dictionary):
if game_data.has("coins"):
print("You have %d coins." % game_data["coins"])
else:
print("You have no coins in your game data!")
3 Likes
hey sorry for being a pest. I would then change a value in a key by doing this?(scavenging from multiple other posts and sites for thisâŚ):
#Adding ONE coin to the wallet
#"savedata" is the savedata dictionary
var current_coins = savedata.get["coins",0]
savedata["coins"] = current_coins + 1
#Or even better? ------->
savedata["coins"] = savedata.get("coins",0) + 1
You can just do this:
savedata["coins"] += 1
# or
savedata["coins"] = savedata["coins"] + 1
âsavedata.get[âcoinsâ, 0]â is not correct syntax
3 Likes
alright! cool. thats very easy. Thank you so much!
1 Like
For posterity! This works â
@export var savefile_data : String #set to "data.cfg" in editor
var data_slotname = "data"
##Dictionary holding the data!
#Values are just defaults.
var data = {
"health": 100.0,
"energy": 0.0,
"damage": 0,
"mumu": 0,
"luck": 0.0,
"goodwill": 0.0,
"bla bla":0
#keep going, keep going!
}
.
.
Saving the entire dictionary
func save_playerdata():
print("Savemanager - Saving all playerdata!")
var savefile = check_savefile(savefile_playerdata)
for key in data.keys():
savefile.set_value(playerdata_slotname, key, data[key])
print("Savemanager - Saving key:",key," : ",data[key])
savefile.save(savefile_playerdata)
.
.
Loading the values from the dictionary (whatever it may contain)
func load_playerdata():
print("Savemanager - Attempting load all playerdata!")
var savefile = check_savefile(savefile_playerdata)
savefile.load(savefile_playerdata)
if !savefile.has_section(playerdata_slotname):
print("Savemanager - Savefile does not have contents. Will be made via the savemanger at begin!")
return
for key in data:
print("Savemanager - Loading all playerdata!")
var value = savefile.get_value(playerdata_slotname, key)
data[key] = value
print("Savemanager - Loading key:",key," : ",data[key])
.
.
.
.
.
Aaaannnnd this function to ease the boiler-plating
func check_savefile(savefile_to_check):
var savefile = ConfigFile.new()
var err = savefile.load(savefile_to_check)
if err != OK:
print("Savemanager - Loading ", savefile_to_check,"failed!")
return null
return savefile
1 Like