Problem with saving a string array (game_save / game_load)

Posted By: Nicros

Problem with saving a string array (game_save / game_load) - 07/23/15 10:19

Hi,
I try to save my game data using the 'game_save' function.
Every time the save is succesful and when I load the game without
closing the program before, the loading also works.
But if I restart the game and want to load the saved game data, the strings don't load correctly.
Therefore i've wrote a short example code:

Code:
#include <acknex.h>
#include <default.c>

STRING* FileNames[256];
int iTest;

function saveLevel();
function loadLevel();
function outpRandomString();

function main()
{
   int i;
   random_seed(0);
   level_load("");
   for(i=0;i<256;i++)
      FileNames[i] = str_create("testName");
   iTest = 1234;
      
   on_f1 = saveLevel;
   on_f2 = loadLevel;
   on_f3 = outpRandomString;
      
   while(1) wait(1);
   return;
}

function saveLevel()   // saving the complete level
{
   int Save = game_save(str_create("test"),1,SV_ALL); // SV_VARS|SV_POINTERS|SV_STRINGS -> also don't works
   if(Save <= 0)
      printf("Error: saving");         
}

function loadLevel()   // loading the save game
{
   int i;
//   for(i=0;i<256;i++)
//      FileNames[i] = "";
        
   int Load = game_load(str_create("test"),1);
   if(Load <= 0)
      printf("Error: Loading");
   
   printf("iTest: %i",iTest);   // correct  
   outpRandomString();   // nothing, rubish or game crash         
}

function outpRandomString()   // outputs the string content at a random index
{
   int i = integer(random(256));   
   printf("Index:%i | String:%s",i,_chr(FileNames[i]));
}



Where is the mistake?
Thanks for help

P.S.: deutsche Antworten sind mir auch sehr recht ;-)
Posted By: EpsiloN

Re: Problem with saving a string array (game_save / game_load) - 07/24/15 06:43

I havent used game_save, but I think you're saving the pointers to a dynamically created strings.

Instead, you should str_cpy the contents of the dynamic string into your pre-defined string. The problem with pointers is that they're different every time you start the app, if they exist at all...
Generate the dynamic string in a 'tempString' and str_cpy tempString to FileNames[i]...

Also, for saving/loading, I dont think its necessary to str_create the name of the save file...you can just use quotes ""
Posted By: Nicros

Re: Problem with saving a string array (game_save / game_load) - 07/24/15 10:08

Thanks for your reply.
I also think that it is a problem with the pointers.
But I don't know how to generate this strings not dynamically.
Because at the beginning the strings point to Zero and I can't use str_cpy() if they don't point to a certain memory region.
Here is my try after your answer:

Code:
STRING* FileNames[256];
STRING* tempStr;

[...]

tempStr = "testName";
for(i=0;i<256;i++)
{
   str_cpy(FileNames[i],tempStr);   //crash: invalid function arguments
}



How would you make this or have you another idea ?

Regards
Posted By: FoxHound

Re: Problem with saving a string array (game_save / game_load) - 07/24/15 15:59

If you simply want to save an array of string don't use the game save but write a txt file and then load back up as needed. The game save setup from 3dgs is designed to load a whole world. Way to complicated and time consuming compared to a simple text file.
Posted By: EpsiloN

Re: Problem with saving a string array (game_save / game_load) - 07/24/15 18:16

At least its a good experience with pointers grin

I'm not sure if you can do this, but try setting all strings to point to an empty dinamically created strings. Just initialize with str_create... all strings in the array, then copy content there. I think it wont work, but its fast to try.

Another way is to use a text object for storing array of strings... Just copy everything you need in them and save.

Using a file is good practise, btw.
Posted By: Nicros

Re: Problem with saving a string array (game_save / game_load) - 07/25/15 09:18

Thanks for your suggestions. It works now laugh (not ... see Edit ->)
I've used the method with the text object because I have to save the whole game but there are two global string arrays defined.
Here is my new code. I've watched the used memory and I think without the 'ptr_remove'-call there will be a memory leak !?
Code:
int i;

[...]

TEXT* txtStringSave = {
   strings=256;
}

[...]

function saveLevel()
{
   for(i=0;i<256;i++)   // save in text object
   {
      str_cpy((txtStringSave.pstring)[i],FileNames[i]);
      // FileNames[i] = NULL;  don't do this -> memory leak
      ptr_remove(FileNames[i]);   // instead   
   }
   int Save = game_save(str_create("test"),1,SV_ALL); // SV_VARS|SV_POINTERS|SV_STRINGS
   if(Save <= 0)
      printf("Error: saving");
   for(i=0;i<256;i++)   // restore array
   {
      FileNames[i] = str_create((txtStringSave.pstring)[i]);
      str_cpy((txtStringSave.pstring)[i],""); 
   }         
}

function loadLevel()
{
   iTest = 0;
        
   int Load = game_load(str_create("test"),1);
   if(Load <= 0)
      printf("Error: Loading");
      
   for(i=0;i<256;i++)   // restore string array
   {
      FileNames[i] = str_create((txtStringSave.pstring)[i]);
      str_cpy((txtStringSave.pstring)[i],""); 
   }
   
   printf("iTest: %i",iTest);  
   outpRandomString();         
}



grin

Edit: Oh, sry... it does not work yet. If I change this line:
Code:
for(i=0;i<256;i++)
   FileNames[i] = str_create("testName");


to this for example:
Code:
for(i=0;i<256;i++)
	   FileNames[i] = str_create("Name");


Then: Script crash in main frown
Any ideas ?
... it seems that it doesn't load the text object correctly.

Posted By: Superku

Re: Problem with saving a string array (game_save / game_load) - 07/25/15 09:53

I haven't had a full look at your code and issue but I don't see a reason to remove or recreate them at all. Just use str_cpy to fill them with new content, once initialized.

Additionally, you overuse str_create way too much. Every time you call str_create you need a corresponding ptr_remove in your code, which means that something like
game_save(str_create("test"),1,SV_ALL);
will result in one new string floating in your memory which you cannot clear because you didn't save the pointer to it. Just write
game_save("test",1,SV_ALL);
instead.
When you keep the strings alive (I suggest you initialize them once at the start of the game) be aware that stuff like
FileNames[i] = str_create((txtStringSave.pstring)[i]);
has to be adapted to a single str_cpy call instead.
Posted By: EpsiloN

Re: Problem with saving a string array (game_save / game_load) - 07/25/15 11:47

Yes, dont destroy your string pointers, there is no need to. The engine will take care of memory leaks for you (thats why we get an engine laugh ).

Another thing, you dont have to use a string array at all, if you're using a text object...It holds your array and has allocated strings by default. You just have to str_copy into or out of them, nothing more...

As for your error, I suggest you wait at least one or two frames before/after you save/load a level.
When you execute a save statement, the program might not have finished everything it was doing to the strings. And, when you're loading, again wait for the program to stop doing anything and then load...And after that, wait one frame to make sure everything is fully loaded and working (or saved...)
Posted By: Nicros

Re: Problem with saving a string array (game_save / game_load) - 07/25/15 15:07

Thanks. I thought that I have to use str_create to convert a char array into a STRING struct cry.
Now I've removed the superfluous str_create calls and use only a text object to store the strings.
But I think that the game_save function doesn't save the content of the text object...
Can I change this behavior ?
Code:
int iTest, i;

function saveLevel();
function loadLevel();
function outpRandomString();

TEXT* txtStringSave = {
   pos_x = 0;
   pos_y = 0;
   strings=256;
   flags = SHOW | LIGHT;
}

function main()
{
   [...]
}

function saveLevel()   
{   
   int Save = game_save("test",1, SV_ALL);
   if(Save <= 0)
      printf("Error: saving");       
}

function loadLevel()
{
   iTest = 0;
   
   int Load = game_load("test",1);
   if(Load <= 0)
      printf("Error: Loading");
   
   printf("iTest: %i",iTest);
   outpRandomString();         
}

function outpRandomString()
{
   i = integer(random(256));   
   printf("Index:%i | String:%s",i,_chr((txtStringSave.pstring)[i]));
}

Posted By: Superku

Re: Problem with saving a string array (game_save / game_load) - 07/25/15 16:19

IMO game_save() is not really intended for any real project, it's just a quick and newbie friendly way (see following limitations) to realize a let's say quicksave and -load feature (which is supposed to save all entity positions and states in a level).
It's a really old command from times where you basically could not create anything but entities dynamically, which is why calling panel or text (/ ...) create instructions break the game_load function. I'd say only use that function on a very simple project which doesn't generate anything dynamically.
Otherwise, do as FoxHound said:
Originally Posted By: FoxHound
If you simply want to save an array of string don't use the game save but write a txt file and then load back up as needed. The game save setup from 3dgs is designed to load a whole world. Way to complicated and time consuming compared to a simple text file.

When it comes to saving your game progress just save some variables into a text file which describe the player's progress sufficiently, then load those variables and create a corresponding game state when necessary.
Posted By: Nicros

Re: Problem with saving a string array (game_save / game_load) - 07/26/15 09:58

Ok, I'll write a save functions on my own.
I have still one question: I've often written something like this in my source code:
Code:
str_cat(str_create("Test"),str_for_num(NULL,testVar));


But this is wrong, because it allocates memory without a deallocation?
I should use _str() instead of str_create() ?
Posted By: Superku

Re: Problem with saving a string array (game_save / game_load) - 07/26/15 11:04

Yes, this is not the correct way to do it.
The unprofessional way to do it (aka my way) is to use some global temporary string:

STRING* str_tmp = "";
..
void dododo(var testnum)
{
str_cpy(str_tmp,"Test");
str_cat(str_tmp,str_for_num(NULL,testnum));
do something with str_tmp, for example "error()" it
}

Alternatively, you could create a string locally and remove it after use:


void dododo(var testnum)
{
STRING* str_tmp;

str_tmp = str_create(""); // of course you can write the "Test" content here, too
str_cpy(str_tmp,"Test");
str_cat(str_tmp,str_for_num(NULL,testnum));
do something with str_tmp, for example "error()" it

ptr_remove(str_tmp);
}


In your case specifically you can use str_printf:
str_printf(NULL,"Test%d",(int)testVar); // see manual -> digits/ format strings
© 2024 lite-C Forums