Game reads from and writes to JSON correctly on my Mac; on Android it reads from but doesn't write to!

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

Hi friends!

My game saves previous scores to a JSON file, and upon user request provides a read-out of recent scores.

On my computer, it does this perfectly. When I export to Android and load it on my phone, the game works fine EXCEPT it does not save any new scores. I know that it is correctly accessing the two JSON files (one of which saves each new day the user plays, the other scores each individual score for each day) because it can pull data from both of them to display the recent scores that were already saved in the JSON files, but it is not saving new scores.

Here’s the code I use for reading FROM the two JSON files:

var file = File.new()
file.open("res://files/scores.json", File.READ)
logged_times = parse_json(file.get_as_text())
file.close()
var file2 = File.new()
file2.open("res://files/scores_DAYS.json", File.READ)
days = parse_json(file2.get_as_text())
file.close()

And here’s how I write TO the files:

var file = File.new()
file.open("res://files/scores.json", File.WRITE)
file.store_line(JSON.print(logged_times))
file.close()
file.open("res://files/scores_DAYS.json", File.WRITE)
file.store_line(JSON.print(days))
file.close()

Any thoughts on what might be happening here? Happy to provide additional code or context if needed.

As always, I so appreciate this community!

File.open() returns an error code that will most probably give you the exact reason it’s not working.

zhyrin | 2023-03-22 17:33

Oh! Okay. Now I’m going to sound stupid. How do I find out what the error code is?

Thank you!!

samjmiller | 2023-03-22 17:56

If you follow the documentation of File.open(), you’ll see that the error code is of an Error enum defined in global scope.
@GlobalScope — Godot Engine (3.5) documentation in English

zhyrin | 2023-03-22 19:19

If I print…

print(file.open("res://files/scores.json", File.READ))

…I get a 0. Which from the documentation you linked to, looks like it means “OK” or “No error occurred.” And then if I print

print(file)

I get [_File:1517], which makes me think that it is finding the file. But when I try to access the data in it with logged_times = parse_json(file.get_as_text()), logged_times comes up Null.

samjmiller | 2023-03-22 20:18

:bust_in_silhouette: Reply From: kidscancode

You can not write to res:// in an exported game -res:// is read-only.

You need to be using user://

See File paths in Godot projects — Godot Engine (latest) documentation in English

That’s helpful, @kidscancode!

I tried simply changing res:// to user://, so that my new path is user://files/scores.json - but now it crashes when I attempt to get the data from the file. So there’s clearly more to it than that, but it eludes me still! I did read the documentation you shared, and it mentions data paths for Windows & Linux & Mac, but not for Android…

samjmiller | 2023-03-22 20:51

Unless your code explicitly creates that files-level folder (or, you’ve interactively created it before hand), simply trying to save a file there will fail - assuming the folder doesn’t exist. If your file needs to be saved in a folder, your code should handle the verification / creation of that folder prior to saving the file.

jgodfrey | 2023-03-22 20:56

Thanks @jgodfrey!

The files subfolder wasn’t necessary, so I moved the files out of it so they’re all stored in the same folder. But still, when I try to write to the file like this:

file.open("user://scores.json", File.WRITE)
file.store_line(JSON.print(days))
file.close()

It doesn’t work in the exported game! On my computer it’s great - reads & writes with res://scores.json (but not with user://scores.json) but not once exported and installed on my Android phone. (When I use a res:// file path, it still works for reading data after export, but not for writing)

Is there something else that needs to be done with the file path? Or a setting? Or do I need to create a new folder prior to saving the file there? And if so… how do I do that?

samjmiller | 2023-03-22 22:55

I think you need a combination of things here:

  • First, you definitely want your file to be stored in user:// as suggested by @kidscancode
  • You do not NEED to create a subfolder, though you certainly could…
  • You need to check the error code returned by open as suggested by @zhyrin. That’d look something like this:

.

var err = file.open("user://scores.json", File.WRITE)
if err == OK:
    file.store_line(JSON.print(logged_times))
    file.close()
else:
    print("File open error: %s" % err)

I assume you’re getting some kind of open error on the Android device, which the above will trap. Though I guess to see it on that device, you’ll need to place the error in some GUI control (or do some remote debugging on the device).

jgodfrey | 2023-03-23 01:34