Jump to content

Save/load config node to custom file on disk [Solved]


Recommended Posts

Nevermind, I gave up on KSPField and decided to store the values in a config node. The config node part is working, but I can't load config nodes from a file on disk. I've looked at this thread on how to do this:

Every time the game loads the config node from the file, the game throws null-reference exceptions as it can't retrieve the config nodes from that file, and thus the config node is never initialised. My method:

public void SaveNode()
{
  string filepath = KSPUtil.ApplicationRootPath + "GameData/BeamedPowerStandalone/PluginData/save.cfg";
  FileInfo info = new FileInfo(filepath);
  ConfigNode BPNode;
  if (info.Length > 0)    // modify later
  {
    BPNode = ConfigNode.Load(KSPUtil.ApplicationRootPath + "GameData/BeamedPowerStandalone/PluginData/save.cfg");
  }
  else
  {
    BPNode = new ConfigNode();
  }
  string vesselId = Convert.ToString(this.vessel.persistentId); int n2 = 0;
  while (n2 < BPNode.nodes.Count)
  {
    if (BPNode.nodes[n2].GetValue("persistentId") == vesselId)
    {
      break;
    }
    n2 += 1;
  }
  ConfigNode CorrectNode = new ConfigNode();
  if (n2 == BPNode.nodes.Count)
  {
    BPNode.AddNode("VESSEL", CorrectNode);
  }
  else
  {
    CorrectNode = BPNode.nodes[n2];
  }
  CorrectNode.SetValue("persistentId", vesselId, createIfNotFound: true);
  CorrectNode.SetValue("wavelength", Wavelength, createIfNotFound: true);
  CorrectNode.SetValue("excess", excess, createIfNotFound: true);
  CorrectNode.SetValue("constant", constant, createIfNotFound: true);

  BPNode.Save(KSPUtil.ApplicationRootPath + "GameData/BeamedPowerStandalone/PluginData/save.cfg");
  //Saves the confignode to disk.
}

save.cfg is a config file in the given directory.

Any help on this is appreciated.

Thanks in advance.

Edited by Aniruddh
Gave up on KSPFields
Link to post
Share on other sites
  • 2 months later...

Hey, I'm having a similar issue. The config nodes save properly, but they don't load. If I do "if (node.HasNode("myNode"))" sometimes it is true and sometimes it's false and just resets everything to the default new settings. I'm looking at the config file, and the node is clearly there, so it should never show "false" unless it's a brand new save. Have you had any luck with your issue? If you have any advice I'd love to hear how you solved your issue.

Link to post
Share on other sites

@Codapop

There were multiple solutions that I had to use to solve this problem, but I think the main one that might be useful to you is this one:

When you write ConfigNode.Load("yourCFGFileDir"), it loads the .cfg file itself as a config node, even if the file contains a 'master' config node. Here is a save-file (which is also treated as a config file) as an example:

GAME
{
	version = 1.8.1
	Title = Exploration (CAREER)
	Description = No description available.
	linkURL = 
	linkCaption = 
	Mode = CAREER
	Status = 1
	Seed = 456562465
	scene = 5
	editor = None
	flag = ContractConfigurator/Agencies/ISRU
	launchID = 111
	defaultVABLaunchSite = LaunchPad
	defaultSPHLaunchSite = Runway
	modded = True
	versionFull = 1.8.1.2694 (WindowsPlayer x64)
	versionCreated = 1.4.5.2243 (WindowsPlayer x64)
	PARAMETERS
	{
		// stuff
	}
	LoaderInfo
	{
		// mods etc.
	}
}

All of the config-nodes here are sub-nodes of the 'GAME' node. If you try to load the save-file config file as a config node and assign it to the variable Savefile, you can't access 'PARAMETERS' using Savefile.GetNode("PARAMETERS"), instead you have to do Savefile.GetNode("GAME").GetNode("PARAMETERS").

This is difficult to explain, hope the example helped.

Link to post
Share on other sites

This is excellent info, thank you!! Can you please tell me how to specify that I want the save-file config as my variable? When I say OnSave(ConfigNode node), is "node" the save file? Or should I just open it like ConfigNode.Load("persistent.sfs")?

Link to post
Share on other sites
14 minutes ago, Codapop said:

This is excellent info, thank you!! Can you please tell me how to specify that I want the save-file config as my variable? When I say OnSave(ConfigNode node), is "node" the save file? Or should I just open it like ConfigNode.Load("persistent.sfs")?

You have to specify the path to the save file, the way this is done is:

ConfigNode SaveNode = ConfigNode.Load(KSPUtil.ApplicationRootPath + "saves/" + HighLogic.SaveFolder + "/persistent.sfs");

Now SaveNode is your entire savefile stored as a config node. The OnLoad(ConfigNode node) method loads a specific config node from the save file, that is only under the respective part module/vessel module node. The latter is generally faster to code, unless you want to access the entire savefile.

Edited by Aniruddh
Link to post
Share on other sites
  • 2 months later...

Hey I know it's been a while, but would you happen to know why this won't work? No matter what it writes 0 to the config file for the value.

 

void SaveTest(ConfigNode node)
        {
            bool flag = node.HasNode("TEST-NODE");
            if (!flag)
            {
                node.AddNode("TEST-NODE");
                ConfigNode node2 = node.GetNode("TEST-NODE");
                node2.AddValue("VALUE", 0);
                Debug.Log("[--------TEST--------]: Save 0");
            }
            else
            {
                ConfigNode node2 = node.GetNode("TEST-NODE");
                node2.SetValue("VALUE", 5);
                Debug.Log("[--------TEST--------]: Save 5");
            }
        }

I've realized that the issue is I'm not actually getting the saved node but rather creating a new one, but I can't figure out a way to get the config file to check if my node is already there. I've tried this:

 

ConfigNode saveNode = ConfigNode.Load(KSPUtil.ApplicationRootPath + "saves/" + HighLogic.SaveFolder + "/persistent.sfs");
            saveNode = saveNode.GetNode("GAME");
            bool flag = saveNode.HasNode("TEST-NODE");
            if (!flag)
            {

                Debug.Log("[--------TEST--------]: " );
                node.AddNode("TEST-NODE");
                ConfigNode node2 = node.GetNode("TEST-NODE");
                node2.AddValue("VALUE", number);
                Debug.Log("[--------TEST--------]: Save " + number);
                number = number + 1;
            }
            else
            {
                ConfigNode node2 = node.GetNode("TEST-NODE");
                node2.SetValue("VALUE", 5);
                Debug.Log("[--------TEST--------]: Save 5");
            }

Still just getting 0. Not really sure what to do. I've tried opening up the file using System.IO and checking it for the String, but it doesn't seem to like that. How do people actually save and retrieve things from nodes?

Link to post
Share on other sites

@Codapop Do you want the SaveTest method to run when a game save happens? If so. you should rename it to OnSave, in which case the parameter 'node' is automatically saved to the save file under the right vessel/part module, so you have less code to write.  If the game automatically saves a config node (through OnSave), it will be saved under the vessel/partmodule  subnode, rather than directly under the "GAME" node.  You would need to navigate to that specific subnode first, which can be  difficult:

Spoiler
	public void SomeMethod()
        {
            ConfigNode Node = ConfigNode.Load(KSPUtil.ApplicationRootPath + "saves/" + HighLogic.SaveFolder + "/persistent.sfs");
            ConfigNode FlightNode = Node.GetNode("GAME").GetNode("FLIGHTSTATE");

            foreach (ConfigNode vesselnode in FlightNode.GetNodes("VESSEL"))
            {
                foreach (ConfigNode partnode in vesselnode.GetNodes("PART"))
                {
                    if (partnode.HasNode("MODULE"))
                    {
                        foreach (ConfigNode module in partnode.GetNodes("MODULE"))
                        {
                            if (module.GetValue("name") == "YourPartModuleName")
                            {
                                bool flag = module.HasNode("TEST-NODE");
				// etc
                            }
                        }
                    }
                }
            }
        }

 

Are you planning to load the config node, from within the same vessel module/part module? In which case you can just use OnLoad(ConfigNode node) instead of the code above.

Hope this helps,

Link to post
Share on other sites

Thanks for the quick feedback! I guess I should explain that I am eventually trying to keep track of science or other resources, so the code will eventually have a "onScienceReceived" function, which I don't believe is attached to a vessel/part module. So far I can get it to record the science properly, but after one save it goes back to 0. I stripped down the code into this test program to see if I could locate the issue, and I can't get it to do a simple count up.

The config node also gets loaded in the same monobehavior, and so far that seems to be working (though it of course always loads in 0).

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...