Hey thank you. Yes I did that and it crashes the second time I save the game. I have NPC Ships which have different values and inventory and player. The player parent path keeps showing like @[email protected] and I have no idea how to fix that. I know you've said that its because Player node is already in the scene but that player node is being deleted every time in that load function at first so I don't understand how its getting duplicated.
Thank you you are right about the habit but I can't see other way around this its insanely complicated at least for me for now.
What I will do I will make only one script which saves all these nodes in separate files. Its only 3 nodes which requires this.
So here is my player load and save:
public void SaveScene()
{
File saveGame = new File();
saveGame.Open("user://player.dat", File.ModeFlags.Write);
Godot.Collections.Array saveNodes = GetTree().GetNodesInGroup("Persist");
foreach (Node saveNode in saveNodes)
{
if (IsAParentOf(saveNode))
{
//Check the node is an instanced scene so it can be instanceds again during load
if (saveNode.Filename.Empty())
{
GD.Print(String.Format("persistent node '{0}' is not an instanced scene, skipping", saveNode.Name));
continue;
}
if (!saveNode.HasMethod("Save"))
{
GD.Print(String.Format("persistent node '{0}' is missing a Save() function, skipping", saveNode.Name));
continue;
}
//Call the nodes save func
var nodeData = saveNode.Call("Save");
//Store the save dictionary as a new line in the save file
saveGame.StoreLine(JSON.Print(Save()));
saveGame.StoreLine(JSON.Print(nodeData));
}
}
saveGame.Close();
}
public void LoadScene()
{
var saveGame = new File();
if (!saveGame.FileExists("user://player.dat"))
return;
var saveNodes = GetTree().GetNodesInGroup("Persist");
foreach (Node saveNode in saveNodes)
{
if (IsAParentOf(saveNode))
{
saveNode.Free();
}
}
//Load the file line by line and process that dictionary to restore the object
//it represents
saveGame.Open("user://player.dat", File.ModeFlags.Read);
bool firstLine = true;
while (saveGame.GetPosition() < saveGame.GetLen())
{
//get the saved dictionary from the next line in the save file
var nodeData = new Godot.Collections.Dictionary<string, object>(
(Godot.Collections.Dictionary)JSON.Parse(saveGame.GetLine()).Result
);
if (!firstLine)
{
//Firstly, we need to create the object and add it to the tree and sets its position
var newObjectScene = (PackedScene)ResourceLoader.Load(nodeData["Filename"].ToString());
Ship newObject = newObjectScene.Instance<Ship>();
newObject.Set("global_position", new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"]));
foreach (KeyValuePair<string, object> entry in nodeData)
{
string key = entry.Key.ToString();
if (key == "Filename" || key == "Parent" || key == "PosX" || key == "PosY")
continue;
newObject.Set(key, entry.Value);
}
AddChild(newObject);
//Now set the remaining variables
//Set up weapons
{
newObject.LoadGameShipWeapons();
}
}
else
{
foreach (KeyValuePair<string, object> entry in nodeData)
{
string key = entry.Key.ToString();
if (key == "Filename")
continue;
string v = "" + entry.Value;
Set(key, entry.Value);
if(key == "credit")
{
credit = Int32.Parse(v);
}
}
firstLine = false;
}
}
saveGame.Close();
}
and here is my normal npc ships load and save:
public void SaveScene()
{
File saveGame = new File();
saveGame.Open("user://npcships.dat", File.ModeFlags.Write);
Godot.Collections.Array saveNodes = GetTree().GetNodesInGroup("Persist");
foreach (Node saveNode in saveNodes)
{
if (IsAParentOf(saveNode))
{
//Check the node is an instanced scene so it can be instanceds again during load
if (saveNode.Filename.Empty())
{
GD.Print(String.Format("persistent node '{0}' is not an instanced scene, skipping", saveNode.Name));
continue;
}
if (!saveNode.HasMethod("Save"))
{
GD.Print(String.Format("persistent node '{0}' is missing a Save() function, skipping", saveNode.Name));
continue;
}
//Call the nodes save func
var nodeData = saveNode.Call("Save");
//Store the save dictionary as a new line in the save file
saveGame.StoreLine(JSON.Print(nodeData));
}
}
saveGame.Close();
}
public void LoadScene()
{
var saveGame = new File();
if (!saveGame.FileExists("user://npcships.dat"))
return;
var saveNodes = GetTree().GetNodesInGroup("Persist");
foreach (Node saveNode in saveNodes)
{
if (IsAParentOf(saveNode))
{
saveNode.QueueFree();
}
}
//Load the file line by line and process that dictionary to restore the object
//it represents
saveGame.Open("user://npcships.dat", File.ModeFlags.Read);
while (saveGame.GetPosition() < saveGame.GetLen())
{
//get the saved dictionary from the next line in the save file
var nodeData = new Godot.Collections.Dictionary<string, object>(
(Godot.Collections.Dictionary)JSON.Parse(saveGame.GetLine()).Result
);
//Firstly, we need to create the object and add it to the tree and sets its position
var newObjectScene = (PackedScene)ResourceLoader.Load(nodeData["Filename"].ToString());
Ship newObject = newObjectScene.Instance<Ship>();
//Now set the remaining variables
foreach (KeyValuePair<string, object> entry in nodeData)
{
string key = entry.Key.ToString();
if (key == "Filename" || key == "Parent" || key == "PosX" || key == "PosY")
continue;
newObject.Set(key, entry.Value);
}
AddChild(newObject);
newObject.Set("global_position", new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"]));
//Set up weapons
{
newObject.LoadGameShipWeapons();
}
}
saveGame.Close();
}
They are different and I don't know how to make all of this in one function...
I also made sure the game auto saves every 10 minutes and when the user exists so it does not waste cycles so much.
Also the ship sometimes that the player is using loads before the player and it crashes the game. Its so complicated I just think that having three separate functions is good enough.
Then what happens is some nodes require those nodes and those some nodes are or arentloaded first and it crashes ah ... my brain is completely gone , if I even had one...