diff --git a/tutorials/io/saving_games.rst b/tutorials/io/saving_games.rst index 5ac6db4d7..b8d78a6d2 100644 --- a/tutorials/io/saving_games.rst +++ b/tutorials/io/saving_games.rst @@ -65,7 +65,7 @@ The save function will look like this: func save(): var save_dict = { - "filename" : get_filename(), + "filename" : get_scene_file_path(), "parent" : get_parent().get_path(), "pos_x" : position.x, # Vector2 is not supported by JSON "pos_y" : position.y, @@ -88,11 +88,11 @@ The save function will look like this: .. code-tab:: csharp - public Godot.Collections.Dictionary Save() + public Godot.Collections.Dictionary Save() { - return new Godot.Collections.Dictionary() + return new Godot.Collections.Dictionary() { - { "Filename", GetFilename() }, + { "Filename", SceneFilePath }, { "Parent", GetParent().GetPath() }, { "PosX", Position.x }, // Vector2 is not supported by JSON { "PosY", Position.y }, @@ -136,12 +136,11 @@ way to pull the data out of the file as well. # Go through everything in the persist category and ask them to return a # dict of relevant variables. func save_game(): - var save_game = File.new() - save_game.open("user://savegame.save", File.WRITE) + var save_game = FileAccess.open("user://savegame.save", FileAccess.WRITE) var save_nodes = get_tree().get_nodes_in_group("Persist") for node in save_nodes: # Check the node is an instanced scene so it can be instanced again during load. - if node.filename.empty(): + if node.scene_file_path.is_empty(): print("persistent node '%s' is not an instanced scene, skipped" % node.name) continue @@ -158,7 +157,6 @@ way to pull the data out of the file as well. # Store the save dictionary as a new line in the save file. save_game.store_line(json_string) - save_game.close() .. code-tab:: csharp @@ -168,34 +166,34 @@ way to pull the data out of the file as well. // dict of relevant variables. public void SaveGame() { - var saveGame = new File(); - saveGame.Open("user://savegame.save", (int)File.ModeFlags.Write); + using var saveGame = FileAccess.Open("user://savegame.save", FileAccess.ModeFlags.Write); var saveNodes = GetTree().GetNodesInGroup("Persist"); foreach (Node saveNode in saveNodes) { // Check the node is an instanced scene so it can be instanced again during load. - if (saveNode.Filename.Empty()) + if (string.IsNullOrEmpty(saveNode.SceneFilePath)) { - GD.Print(String.Format("persistent node '{0}' is not an instanced scene, skipped", saveNode.Name)); + GD.Print($"persistent node '{saveNode.Name}' is not an instanced scene, skipped"); continue; } // Check the node has a save function. if (!saveNode.HasMethod("Save")) { - GD.Print(String.Format("persistent node '{0}' is missing a Save() function, skipped", saveNode.Name)); + GD.Print($"persistent node '{saveNode.Name}' is missing a Save() function, skipped"); continue; } // Call the node's save function. var nodeData = saveNode.Call("Save"); - // Store the save dictionary as a new line in the save file. - saveGame.StoreLine(JSON.Print(nodeData)); - } + // JSON provides a static method to serialized JSON string + var jsonString = JSON.Stringify(nodeData); - saveGame.Close(); + // Store the save dictionary as a new line in the save file. + saveGame.StoreLine(jsonString); + } } @@ -212,8 +210,7 @@ load function: # Note: This can be called from anywhere inside the tree. This function # is path independent. func load_game(): - var save_game = File.new() - if not save_game.file_exists("user://savegame.save"): + if not FileAccess.file_exists("user://savegame.save"): return # Error! We don't have a save to load. # We need to revert the game state so we're not cloning objects @@ -226,8 +223,10 @@ load function: # Load the file line by line and process that dictionary to restore # the object it represents. - save_game.open("user://savegame.save", File.READ) - while save_game.get_position() < save_game.get_len(): + var save_game = FileAccess.open("user://savegame.save", FileAccess.READ) + while save_game.get_position() < save_game.get_length(): + var json_string = save_game.get_line() + # Creates the helper class to interact with JSON var json = JSON.new() @@ -251,16 +250,13 @@ load function: continue new_object.set(i, node_data[i]) - save_game.close() - .. code-tab:: csharp // Note: This can be called from anywhere inside the tree. This function is // path independent. public void LoadGame() { - var saveGame = new File(); - if (!saveGame.FileExists("user://savegame.save")) + if (!FileAccess.FileExists("user://savegame.save")) return; // Error! We don't have a save to load. // We need to revert the game state so we're not cloning objects during loading. @@ -273,30 +269,39 @@ load function: // Load the file line by line and process that dictionary to restore the object // it represents. - saveGame.Open("user://savegame.save", (int)File.ModeFlags.Read); + using var saveGame = FileAccess.Open("user://savegame.save", FileAccess.ModeFlags.Read); - while (saveGame.GetPosition() < saveGame.GetLen()) + while (saveGame.GetPosition() < saveGame.GetLength()) { - // Get the saved dictionary from the next line in the save file - var nodeData = new Godot.Collections.Dictionary((Godot.Collections.Dictionary)JSON.Parse(saveGame.GetLine()).Result); + var jsonString = saveGame.GetLine(); + + // Creates the helper class to interact with JSON + var json = new JSON(); + var parseResult = json.Parse(jsonString); + if (parseResult != Error.Ok) + { + GD.Print($"JSON Parse Error: {json.GetErrorMessage()} in {jsonString} at line {json.GetErrorLine()}"); + continue; + } + + // Get the data from the JSON object + var nodeData = new Godot.Collections.Dictionary((Godot.Collections.Dictionary)json.Data); // Firstly, we need to create the object and add it to the tree and set its position. var newObjectScene = (PackedScene)ResourceLoader.Load(nodeData["Filename"].ToString()); var newObject = (Node)newObjectScene.Instantiate(); GetNode(nodeData["Parent"].ToString()).AddChild(newObject); - newObject.Set("Position", new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"])); + newObject.Set("position", new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"])); // Now we set the remaining variables. - foreach (KeyValuePair entry in nodeData) + foreach (KeyValuePair entry in nodeData) { - string key = entry.Key.ToString(); + string key = entry.Key; if (key == "Filename" || key == "Parent" || key == "PosX" || key == "PosY") continue; newObject.Set(key, entry.Value); } } - - saveGame.Close(); }