Problem with accessing saved data in Godot 4.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By MaybeAnonymous

So I tried making a save file for my game, so that the user can keep their settings even after the game is closed. I followed this tutorial and I tried changing some things to fit Godot 4 by reading documentation.

I get this when running the game Invalid get index 'play_music' (on base: 'Dictionary')., for context, here’s the code that gives this error:

# music.gd - added to AudioStreamPlayer nodes who play music.
extends AudioStreamPlayer

func _ready():
    # Only play music if it is configured to do so.
    if FileAccess.file_exists(Settings.SAVED_SETTINGS_FILE):
        playing = Settings.settings_data["play_music"]

And here is Settings:

# settings.gd - This file is autoload.
extends Node

const SAVED_SETTINGS_FILE := "user://saved_settings.save"

var settings_data: Dictionary = {}

func _ready() -> void:
    save_settings()
    load_settings()

func save_settings() -> void:
    var file = FileAccess.open(SAVED_SETTINGS_FILE, FileAccess.WRITE)
    file.store_var(settings_data)

func load_settings() -> Dictionary:
    if not FileAccess.file_exists(SAVED_SETTINGS_FILE):
        settings_data = {
            "auto_walk": true,
            "play_music": true,
        }
        save_settings()
    var file = FileAccess.open(SAVED_SETTINGS_FILE, FileAccess.READ)
    settings_data = file.get_var()
    
    # I'm not sure if this is necessary, but it was in the documentation.
    return settings_data

I don’t really know why this is happening, although it could be that music.gd’s _ready() function is being called before setting.gd’s.

I tried using resources which caused a lot of problems that were too complex for me and I heard they can run arbitrary code so I decided to try something else.

user:// here is in ~/.local/share/godot/app_userdata/game_name (I’m on Linux) which I have read and write permissions to, and saved_settings.save is present there.

Edit: This doesn’t actually fix it, the issue only happens when the save file doesn’t exist yet

I just had to change the save file from user://saved_settings.save (what the video used) to user://saved_settings.dat, I found it after re-reading the FileAccess documentation.

Here’s what settings.gd looks like now (not many changes):

extends Node

const SAVED_SETTINGS_FILE := "user://saved_settings.dat"

var settings_data: Dictionary 

func _ready() -> void:
    #save_settings()
    load_settings()

func save_settings() -> void:
    var file = FileAccess.open(SAVED_SETTINGS_FILE, FileAccess.WRITE)
    file.store_var(settings_data)
    file = null

func load_settings() -> Dictionary:
    if not FileAccess.file_exists(SAVED_SETTINGS_FILE):
        settings_data = {
            "auto_walk": true,
            "play_music": true,
        }
        save_settings()
    var file = FileAccess.open(SAVED_SETTINGS_FILE, FileAccess.READ)
    settings_data = file.get_var()
    file = null
    
    # Unsure if this is necessary, but it was in the documentation.
    return settings_data

MaybeAnonymous | 2022-12-24 16:34

Well, technically I fixed it with this but I also didn’t, I had to remove the save file then hope for the best, I’ll test a bit more and decide whether this is good enough, but would be nice to have a way that just works

MaybeAnonymous | 2022-12-24 16:53

:bust_in_silhouette: Reply From: MaybeAnonymous

Okay, it kind of works now?

I had to make @onready variables for Settings.settings_data and changed the file format to .dat and then deleted the save files