Making games
Files
File reads and writes files from a script, for what Save and Settings are
not for: a level a player made, a replay, a text log, or data your game ships
with, such as a list of levels. Every call is listed in the
Cog API reference.
Two places, and nothing else
A file is named by an address that starts with one of these:
| Address | What it is |
|---|---|
user://... | This game’s folder on the player’s computer. Read and write. |
assets://... | The game’s own files, the ones in your project’s assets folder. Read only. |
That is all a script can reach. A path like C:/notes.txt is an error that says
what is allowed, and .. cannot climb out of either folder. People will run
each other’s games, and a game that can only touch its own folder cannot read or
change another game’s files, or anything else on the computer.
user:// is the same folder Save and Settings use, named for your game
(see Where it is kept). Folders are
made as you write, so there is no call to make one.
Writing and reading
fn write_notes(text) {
File.write_all_text("user://notes/today.txt", text)
}
fn read_notes() {
var text = File.read_all_text("user://notes/today.txt")
if text == null {
return "No notes yet"
}
return text
}
Reading a file that is not there gives null, not an error: a missing file is
an ordinary answer. A write that fails (the disk is full, or the folder is not
allowed) stops the script with an error that names the file and the reason. Every
write is the safe kind described under
A crash cannot cut a save off.
To carry on after a failed write, catch it:
fn keep_notes(text) {
try {
File.write_all_text("user://notes/today.txt", text)
} catch (e) {
log.error(e)
}
}JSON
File.read_json and File.write_json read and write a value as JSON, which
other programs can read too:
fn load_level(name) {
var level = File.read_json("assets://levels/{name}.json")
if level == null {
log.warn("No level called {name}")
}
return level
}
fn save_level(name, level) {
File.write_json("user://levels/{name}.json", level)
}
JSON has no Vec3, so one is written as an object of its numbers, and reads back
as an object, not a Vec3 (the reference lists how each type is written). For
data your own game reads back as it was, use Save.
Listing a folder
File.list gives the names in a folder, sorted, with a / after each folder’s
name:
fn level_names() {
var names = []
for name in File.list("user://levels") {
if name.ends_with(".json") {
names.push(name)
}
}
return names
}
A folder that is not there is an empty list. On assets:// the list comes from
your project’s asset list, so it gives the same names in the editor and in the
built game.