Game Development Community

Any way to exec a saved file?

by Laralyn McWilliams · in Torque Game Builder · 06/05/2010 (10:36 pm) · 20 replies

In a forum post from a while back, I read a great suggestion about writing saved game files as executable script, so rather than go through the line by line loading and assignment to variables, you just exec() the file in a single step.

That sounds awesome... but when I use an exec() command it only seems to look in the game's working folder structure rather than in the relative save path of %APPDATA%. Save/load with fileIO works fine in the %APPDATA% default paths.

Is there something special I should use in the path for exec() that would make this work? It would be really helpful to save my game data straight out to CS files!

Thanks! :-)

#1
06/06/2010 (12:50 am)
I can tell you that I do something very similar to the following:

// Save Code
new FileObject( LabyrinthFile );
LabyrinthFile.openForWrite( "savedGames/state.txt" );
LabyrinthFile.writeObject( LState );
LabyrinthFile.close();
LabyrinthFile.delete();

// Load Code
exec( "savedGames/state.txt" );

(I actually put the files into a directory using the player's name, but that's unnecessary for this example.)

This creates a directory under "%APPDATA%/MachineCodeGames/Labyrinth" called "savedGames". The exec() then reads from that same directory automatically.

You might double check that you are using the same directory/name for the save and load. If you're still having problems, just let me know.
#2
06/06/2010 (4:22 am)
Oh how I wish the saved game state worked for me. I spent 3 days going line by line restoring variables and ensuring the correct timing. Oh well. Interestingly my save files are about 5k instead of 600k.
#3
06/06/2010 (10:43 am)
I figured out what the problem is. Something in my game has gone haywire. I set up the properties.cs so the company name is Eluminarts and the game name is RPG. Then all my saves are relative, like this: ./game/data/test.txt

It looks like as of 5/31, it was saving all the data (correctly) here:

C:\Users\Laralyn\AppData\Roaming\Eluminarts\RPG\game\gameScripts\saves

This morning (and presumably ever since 5/31), it's now saving my data here instead:

C:\Users\Laralyn\AppData\Roaming\GarageGames\Torque Game Builder\game\gameScripts\saves

I never noticed because the data was loading in correctly. The only reason I noticed last night was because I created the file I'm reading in manually and dropped it into the Eluminarts path.

Why would this suddenly change? How can I fix it?
#4
06/06/2010 (11:02 am)
Another wrinkle:

If during the same play session, I create the .txt file, exec() looks in the correct path. If I don't create the file during the session but just try to read it in instead, exec() looks in the working game path. The exec() command is the same in both cases:

exec("./saves/save1.txt");

I know it's confusing, so here's what the output says in each case:

If I save out the file in the same session:

Executing C:/Users/Laralyn/AppData/Roaming/GarageGames/Torque Game Builder/game/gameScripts/saves/save1.txt.

If I DON'T save out the file that session but simply try to read it in:

Missing file: C:/Users/Laralyn/Documents/My Dropbox/RPG/Code/RPG/game/gameScripts/saves/save1.txt!

It looks like exec() only looks in the %APPDATA% path for a specific file if that file has been saved out during the current session.
#5
06/06/2010 (2:03 pm)
Very odd, indeed!

First, make sure common/commonConfig.xml has the correct company and game name information.

Next, have you modified common/main.cs's onStart()?

Finally, have you modified game/main.cs?

I'm wondering if you've modified the initialization order and maybe (hopefully) that is causing the problem.

I definitely save and exec in separate sessions, as I use the save files to set-up certain conditions for testing and use them over and over. So I know it's possible for this to work.

Let me know what you find out!
#6
06/06/2010 (2:37 pm)
Wacky--somehow the commonConfig.xml file was blown away. Everything in it was blank, like this:

<Company></Company>

It didn't even have the company as Independent, etc. that the file usually has in it by default. I wonder what affected the file like that?

Once I entered the correct info into that file, everything started working correctly again!

Thanks so much for the help. I never would have figured that out on my own!
#7
06/06/2010 (2:58 pm)
OK, something is seriously messed up. I fixed the commonConfig.xml file and everything ran perfectly... twice. Then I ran a third time to test some changes, and it was broken again. I checked the commonConfig.xml file, and now it looks like this:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<TorqueGameConfiguration>
   <Company />
   <GameName />
   <Resolution>1024 768 32</Resolution>
   <FullScreen />
   <CommonVer />
   <ConsoleKey />
   <ScreenShotKey />
   <FullscreenKey />
   <UsesNetwork />
   <UsesAudio />
   <DefaultScene>~/data/levels/entrance_1.t2d</DefaultScene>
</TorqueGameConfiguration>

Not only was the data I entered a few minutes ago gone, but whatever happened seems to have warped the file in a really weird way, where this:

<Company>Eluminarts</Company>

became this:

<Company />

What the heck is going on?
#8
06/06/2010 (3:01 pm)
Sorry for the multiple posts, but I figured you might ask about the main.cs file. I haven't edited that file at all. Here's what it looks like:

//---------------------------------------------------------------------------------------------
// Torque Game Builder
// Copyright (C) GarageGames.com, Inc.
//---------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------
// CommonPackage
// Adds functionality for this mod to some standard functions.
//---------------------------------------------------------------------------------------------
package CommonPackage
{
//---------------------------------------------------------------------------------------------
// onStart
// Called when the engine is starting up. Initializes this mod.
//---------------------------------------------------------------------------------------------
function onStart()
{
   Parent::onStart();

   echo(" % - Initializing Common");
   
   // Load preferences.
   exec("./preferences/defaultPrefs.cs");   
   exec("./gameScripts/xml.cs");
   exec("./gameScripts/properties.cs");
   
   _defaultGameconfigurationData();
   _loadGameConfigurationData( expandFileName("./commonConfig.xml") );
      
   // Initialise stuff.
   exec("./gameScripts/common.cs");
   
   initializeCommon();
}

//---------------------------------------------------------------------------------------------
// onExit
// Called when the engine is shutting down. Shutdowns this mod.
//---------------------------------------------------------------------------------------------
function onExit()
{   
   _saveGameConfigurationData( expandFileName("./commonConfig.xml") );
   _shutdownCommon();

   Parent::onExit();
}

function loadKeybindings()
{
   $keybindCount = 0;
   // Load up the active projects keybinds.
   if(isFunction("setupKeybinds"))
      setupKeybinds();
}

//---------------------------------------------------------------------------------------------
// displayHelp
// Prints the command line options available for this mod.
//---------------------------------------------------------------------------------------------
function displayHelp() {
   // Let the parent do its stuff.
   Parent::displayHelp();

   error("Common Mod options:\n" @
         "  -fullscreen            Starts game in full screen mode\n" @
         "  -windowed              Starts game in windowed mode\n" @
         "  -autoVideo             Auto detect video, but prefers OpenGL\n" @
         "  -openGL                Force OpenGL acceleration\n" @
         "  -directX               Force DirectX acceleration\n" @
         "  -voodoo2               Force Voodoo2 acceleration\n" @
         "  -prefs <configFile>    Exec the config file\n");
}

//---------------------------------------------------------------------------------------------
// parseArgs
// Parses the command line arguments and processes those valid for this mod.
//---------------------------------------------------------------------------------------------
function parseArgs()
{
   // Let the parent grab the arguments it wants first.
   Parent::parseArgs();

   // Loop through the arguments.
   for (%i = 1; %i < $Game::argc; %i++)
   {
      %arg = $Game::argv[%i];
      %nextArg = $Game::argv[%i+1];
      %hasNextArg = $Game::argc - %i > 1;
   
      switch$ (%arg)
      {
         case "-fullscreen":
            $pref::Video::fullScreen = 1;
            $argUsed[%i]++;

         case "-windowed":
            $pref::Video::fullScreen = 0;
            $argUsed[%i]++;

         case "-openGL":
            $pref::Video::displayDevice = "OpenGL";
            $argUsed[%i]++;

         case "-directX":
            $pref::Video::displayDevice = "D3D";
            $argUsed[%i]++;

         case "-voodoo2":
            $pref::Video::displayDevice = "Voodoo2";
            $argUsed[%i]++;

         case "-autoVideo":
            $pref::Video::displayDevice = "";
            $argUsed[%i]++;

         case "-prefs":
            $argUsed[%i]++;
            if (%hasNextArg) {
               exec(%nextArg, true, true);
               $argUsed[%i+1]++;
               %i++;
            }
            else
               error("Error: Missing Command Line argument. Usage: -prefs <path/script.cs>");
      }
   }
}

};

activatePackage(CommonPackage);
#9
06/06/2010 (3:11 pm)
I know this is probably a very long stretch, but have you modified common/gameScripts/xml.cs or the source code's SimXMLDocument?

When TGB exits, it saves back to this XML file (I think mostly for the default scene to be set) using the two parts I just mentioned.

If that's not the case, I'd recommend something fairly radical: re-install TGB and copy your .cs files and any source code changes you've made over to the new installation. It's not painful, but it can be error prone if you miss a file.
#10
06/06/2010 (3:16 pm)
I don't know enough to modify xml.cs or the source code, LOL! :-)

Does it work to also copy the level files over to a new installation? That's where most of the work has been in the project so far.
#11
06/06/2010 (3:38 pm)
Yep, you can definitely copy over the level files, too. In fact, as long as you install it into the same directory, it should be safe to copy over everything under the game directory (behavior, data, gameScripts, gui, help, and managed).

The managed directory will have your image datablocks, but they will only work if you use the same directory name. The levels files under the data directory will only work if you use the same image datablock names (which is really easy if you used the default names).

I sure do hope this works for you! (My fingers are crossed.)
#12
06/06/2010 (5:14 pm)
I created a new project with the same name/path, copied the files over, and everything seems to be running fine. Thanks again for the help!

I'll keep an eye on the .xml file and if it breaks again, I'll try to get repro steps and enter a bug report on it. I did crash once while TGB was open, so maybe that caused the odd behavior.
#13
06/06/2010 (11:26 pm)
It just started happening again, writing all new goofy nonsense into the .xml file. Here's what the .xml file says this time:

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<TorqueGameConfiguration>
   <Eluminarts>Eluminarts</Eluminarts>
   <RPG>RPG</RPG>
   <Resolution>1024 768 32</Resolution>
   <FullScreen>false</FullScreen>
   <CommonVer>114</CommonVer>
   <ConsoleKey>tilde</ConsoleKey>
   <ScreenShotKey>ctrl p</ScreenShotKey>
   <FullscreenKey>alt enter</FullscreenKey>
   <UsesNetwork>0</UsesNetwork>
   <UsesAudio>1</UsesAudio>
   <DefaultScene>~/data/levels/entrance_1.t2d</DefaultScene>
</TorqueGameConfiguration>

It's replaced the <Company> and <GameName> tags with what should be written inside the tags!

It was working for a while... and just broke for no apparent reason. I created another new TGB project with the same name, manually copied all the files over, and in the new project it looks in the paths correctly and everything is fine.

So I think I have uncovered a bug in TGB... but I have no idea how to repro it yet. I'll keep an eye on that .xml file for the next time it goes haywire, and see if I can figure out what I'm doing right before it changes.
#14
06/07/2010 (2:14 am)
Did TGB crash at any time during this?
#15
06/07/2010 (2:32 pm)
TGB crashed a while back (maybe three weeks ago). That was before I reinstalled TGB and created a new project, then copied all the files over by hand. When it happened again yesterday, it was in that entirely new, re-installed project.
#16
06/07/2010 (3:58 pm)
My last and only idea is that properties.cs changed. Could you go into common/gameScripts/properties.cs and copy the _saveGameConfigurationData function here?
#17
06/07/2010 (10:05 pm)
Here's what the current properties.cs file has (in what I think is a clean project file that hasn't shown that weird bug... yet):

function _saveGameConfigurationData( %projectFile )
{
   %xml = new ScriptObject() { class = "XML"; };
   if( %xml.beginWrite( %projectFile ) )
   {
      %xml.writeClassBegin( "TorqueGameConfiguration" );
         %xml.writeField( "Company", $Game::CompanyName );
         %xml.writeField( "GameName", $Game::ProductName );
         %xml.writeField( "Resolution", $Game::Resolution );
         %xml.writeField( "FullScreen", $Game::FullScreen );
         %xml.writeField( "CommonVer", $Game::CommonVersion );
         %xml.writeField( "ConsoleKey", $Game::ConsoleBind );
         %xml.writeField( "ScreenShotKey", $Game::ScreenshotBind );
         %xml.writeField( "FullscreenKey", $Game::FullscreenBind );
         %xml.writeField( "UsesNetwork", $Game::UsesNetwork );
         %xml.writeField( "UsesAudio", $Game::UsesAudio );
         %xml.writeField( "DefaultScene", $Game::DefaultScene );
      %xml.writeClassEnd();
      %xml.endWrite();
   }   
   else
   {
      error( "saveGameConfigurationData - Failed to write to file: " @ %projectFile );
      return false;
   }
   
   // Delete the object
   %xml.delete();
   
   return true;
}

And here is the same section from one of the older projects that was having the problem:

function _saveGameConfigurationData( %projectFile )
{
   %xml = new ScriptObject() { class = "XML"; };
   if( %xml.beginWrite( %projectFile ) )
   {
      %xml.writeClassBegin( "TorqueGameConfiguration" );
         %xml.writeField( "Eluminarts", $Game::CompanyName );
         %xml.writeField( "RPG", $Game::ProductName );
         %xml.writeField( "Resolution", $Game::Resolution );
         %xml.writeField( "FullScreen", $Game::FullScreen );
         %xml.writeField( "CommonVer", $Game::CommonVersion );
         %xml.writeField( "ConsoleKey", $Game::ConsoleBind );
         %xml.writeField( "ScreenShotKey", $Game::ScreenshotBind );
         %xml.writeField( "FullscreenKey", $Game::FullscreenBind );
         %xml.writeField( "UsesNetwork", $Game::UsesNetwork );
         %xml.writeField( "UsesAudio", $Game::UsesAudio );
         %xml.writeField( "DefaultScene", $Game::DefaultScene );
      %xml.writeClassEnd();
      %xml.endWrite();
   }   
   else
   {
      error( "saveGameConfigurationData - Failed to write to file: " @ %projectFile );
      return false;
   }
   
   // Delete the object
   %xml.delete();
   
   return true;
}

I never manually edited that section of that file... and yet there's where it somehow substituted Eluminarts for Company, and RPG for ProductName.

I kept all the busted projects in case I needed them, and here's what that same function looked like in the version that was printing blanks for Company and ProductName:

function _saveGameConfigurationData( %projectFile )
{
   %xml = new ScriptObject() { class = "XML"; };
   if( %xml.beginWrite( %projectFile ) )
   {
      %xml.writeClassBegin( "TorqueGameConfiguration" );
         %xml.writeField( "Company", $Game::Eluminarts );
         %xml.writeField( "GameName", $Game::RPG );
         %xml.writeField( "Resolution", $Game::Resolution );
         %xml.writeField( "FullScreen", $Game::FullScreen );
         %xml.writeField( "CommonVer", $Game::CommonVersion );
         %xml.writeField( "ConsoleKey", $Game::ConsoleBind );
         %xml.writeField( "ScreenShotKey", $Game::ScreenshotBind );
         %xml.writeField( "FullscreenKey", $Game::FullscreenBind );
         %xml.writeField( "UsesNetwork", $Game::UsesNetwork );
         %xml.writeField( "UsesAudio", $Game::UsesAudio );
         %xml.writeField( "DefaultScene", $Game::DefaultScene );
      %xml.writeClassEnd();
      %xml.endWrite();
   }   
   else
   {
      error( "saveGameConfigurationData - Failed to write to file: " @ %projectFile );
      return false;
   }
   
   // Delete the object
   %xml.delete();
   
   return true;
}

So yes, whatever is causing the bug seems to be doing the wacky rewrites in that file... which I never touch manually and I assume the code shouldn't be changing either?
#18
06/07/2010 (11:36 pm)
EEK! I searched all of the source code and scripts to see if anything would modify this file and it appears that nothing does.

Are you maybe doing global search-and-replaces? Truely, that is my last hope here. The fact that it's changed it in two different areas is even more odd. I might go so far as to say you have a gremlin in your machine playing tricks on your code just to throw you off.
#19
06/08/2010 (8:33 am)
Can you do a global search and replace in Torsion? I've done global searches, but only single file "Replace All" commands. And I know I've never done a replace all on Eluminarts or RPG.

I'll watch that file as I work in the new project and see if I can pin down when it gets changed (assuming it happens again).
#20
06/08/2010 (1:41 pm)
Not in Torsion, but I have (on very rare occasions) done it through Visual C++.

Anywho... I hope it never comes back, but if it does, I'll keep an eye on this post.