+1 vote

I am trying to make a directory in my user:// location to save a player's game data to a text file. here is my code. It is in an autoloaded script and is called once the user finished the game.

func _save():
    var directory = Directory.new()

    if directory.dir_exists("user://save/" + UserInput.playername + "/"): 
        print("Directory exists!")
    else: 
        directory.make_dir("user://save/" + UserInput.playername "/")
        print("Made directory!")

    var FILE_NAME = "user://save/" + UserInput.playername + "/" + str(month) + "_" + str(day) + "_" + str(year) + ".txt"
    var data = ""
    data += "Time: " + str(hour) + ":" + str(minute)
    data += "Level: " + str(level)
    data += "Target_Objects_Points: " + str(targetObjectsPoints)
    data += "\n"
    data += "Distractor_Objects_Points: " + str(distractorObjectsPoints)
    data += "\n"
    data += "Missed_Objects: " + str(missedObjectsPoints)
    data += "\n"
    var new_file = File.new()
    new_file.open(FILE_NAME, File.READ_WRITE)
    new_file.seek_end()
    #Store the data and close the file
    new_file.store_line(data)
    new_file.close()
    print("file saved!")

I am trying to create a directory for any new player who plays the game (hence directory.make_dir("user://save/" + UserInput.playername).

My idea is that the first time the player starts the game, a folder that will store their data gets created. Then, the file name in that folder reflects the date. All data from that game on that date would get appended into one text file. I know this isn't conventional, but I am using Godot to create a video game for research purposes, so I need access to data according to specific players and dates.

The output says it is creating the directory, and that it is saving it, but when I navigate to my user:// location, nothing is there. I am also getting an error that says ERROR: File must be opened before use.

What am I doing wrong here? am I creating the folder incorrectly? Something wrong with my save code?

in Engine by (45 points)
edited by

1 Answer

+1 vote
Best answer

I got your code to work. Here's the problems that I noticed and how I fixed them:

Problem 1
When you call directory.make_dir(), it returns an Error. I added an if statement to tell me about the error:

const DIR_ERROR = 'ERROR: Failed to create directory "%s". Error code %s.'
...
func _save():
    var directory = Directory.new()

    var DIR_PATH = "user://save/" + UserInput.playername + "/"
    if directory.dir_exists(DIR_PATH):
        print("Directory exists!")
    else:
        var error_code = directory.make_dir(DIR_PATH)
        if error_code != OK:
            printerr(DIR_ERROR % [DIR_PATH, error_code])

Specifically, the Error was 20, ERR_CANT_CREATE. The Error was being caused by the fact that the "save" directory didn't exist, so the UserInput.playername directory couldn't be created inside of it. Here's two possible solutions to problem 1:

const DIR_ERROR = 'ERROR: Failed to create directory "%s". Error code %s.'

# This is only needed for potential solution 1.
func try_to_create_dir(directory, path):
    if not directory.dir_exists(path):
        var error_code = directory.make_dir(path)
        if error_code != OK:
            printerr(DIR_ERROR % [path, error_code])

func _save():
    var directory = Directory.new()

    # Potential solution 1:
    try_to_create_dir(directory, "user://save")
    try_to_create_dir(directory, "user://save/" + UserInput.playername)

    # Potential solution 2:
    var DIR_PATH = "user://save/" + UserInput.playername + "/"
    if directory.dir_exists(DIR_PATH):
        print("Directory exists!")
    else:
        var error_code = directory.make_dir_recursive(DIR_PATH)
        if error_code != OK:
            printerr(DIR_ERROR % [DIR_PATH, error_code])

Problem 2
When you call new_file.open(), it returns an Error. I added an if statement to tell me about the error:

const OPEN_ERROR = 'ERROR: Failed to open "%s". Error code %s.'
...
func _save():
...
    var error_code = new_file.open(FILE_NAME, File.READ_WRITE)
    if error_code == OK:
        new_file.seek_end()
        #Store the data and close the file
        new_file.store_line(data)
        new_file.close()
        print("file saved!")
    else:
        printerr(OPEN_ERROR % [FILE_NAME, error_code])

Specifically, the Error was 7, ERR_FILE_NOT_FOUND. Here's what Godot's documentation says about opening a file for writing:

Opens the file for write operations. The file is created if it does not exist, and truncated if it does.

Here's what it says about opening a file for reading and writing:

Opens the file for read and write operations. Does not truncate the file. The cursor is positioned at the beginning of the file.

Since you're opening the file for reading and writing, the file's not getting created when it doesn't exist. Here's my solution for that problem:

const OPEN_ERROR = 'ERROR: Failed to open "%s". Error code %s.'
...
func _save():
    var error_code
    if new_file.file_exists(FILE_NAME):
        error_code = new_file.open(FILE_NAME, File.READ_WRITE)
    else:
        error_code = new_file.open(FILE_NAME, File.WRITE)

    if error_code == OK:
        new_file.seek_end()
        #Store the data and close the file
        new_file.store_line(data)
        new_file.close()
        print("file saved!")
    else:
        printerr(OPEN_ERROR % [FILE_NAME, error_code])

Conclusion
In the end, here's what my code loked like:

const OPEN_ERROR = 'ERROR: Failed to open "%s". Error code %s.'
const DIR_ERROR = 'ERROR: Failed to create directory "%s". Error code %s.'

func _save():
    var directory = Directory.new()

    # Potential solution 1:
    try_to_create_dir(directory, "user://save")
    try_to_create_dir(directory, "user://save/" + UserInput.playername)

    # Potential solution 2:
    var DIR_PATH = "user://save/" + UserInput.playername + "/"
    if directory.dir_exists(DIR_PATH):
        print("Directory exists!")
    else:
        var error_code = directory.make_dir_recursive(DIR_PATH)
        if error_code != OK:
            printerr(DIR_ERROR % [DIR_PATH, error_code])

    var FILE_NAME = DIR_PATH + str(month) + "_" + str(day) + "_" + str(year) + ".txt"
    var data = ""
    data += "Time: " + str(hour) + ":" + str(minute)
    data += "Level: " + str(level)
    data += "Target_Objects_Points: " + str(targetObjectsPoints)
    data += "\n"
    data += "Distractor_Objects_Points: " + str(distractorObjectsPoints)
    data += "\n"
    data += "Missed_Objects: " + str(missedObjectsPoints)
    data += "\n"
    var new_file = File.new()

    var error_code
    if new_file.file_exists(FILE_NAME):
        error_code = new_file.open(FILE_NAME, File.READ_WRITE)
    else:
        error_code = new_file.open(FILE_NAME, File.WRITE)

    if error_code == OK:
        new_file.seek_end()
        #Store the data and close the file
        new_file.store_line(data)
        new_file.close()
        print("file saved!")
    else:
        printerr(OPEN_ERROR % [FILE_NAME, error_code])
by (363 points)
selected by

wow. This worked! I went with potential solution 2, as it made more sense to me. I just want to say thank you SO much and this is absolutely fabulous. Your generosity is truly appreciated

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.