Highscore saving and loading to a file

edited November 2014 in Help request
Spent a bit of time this evening working out the best way to save a highscore to a file and then be able to retrieve it again.

The save is working ok, the load less so.

I have taken most of my info from the API at: http://orx-project.org/orx/doc/html/group__orx_file.html

and also the notes at: https://groups.google.com/forum/?hl=en#!topic/orx-dev/hsyn1nSL3ck

The code I have come up with so far is:
const orxSTRING zSaveFile = orxFile_GetApplicationSaveDirectory("OrxTest/Save.ini");
	orxLOG("Dir %s", zSaveFile);
	
	orxFILE *file = orxFile_Open(zSaveFile, orxFILE_KU32_FLAG_OPEN_WRITE);
	orxFile_Print(file, (orxCHAR*)"5561111"); //print score to file	
	orxFile_Close(file); //complete write
	
	orxFILE *fileToReadBack = orxFile_Open(zSaveFile, orxFILE_KU32_FLAG_INFO_READONLY);
	
	orxSTRING readBackString = (orxCHAR*)"1234567";
	int numRead = orxFile_Read( readBackString, sizeof(orxCHAR), 7, fileToReadBack	);
	
	orxLOG("Read amount %d, back as string: %s", numRead, readBackString);


The result I get back is:
Read amount 0, back as string: 1234567

Which indicates the load brought back 0 chars, and 1234567 was not overwritten with 5561111.

Comments

  • edited November 2014
    This is tough. Revised to:
    const orxSTRING zSaveFile = "./OrxTest/Save.ini"; 
        orxLOG("Dir %s", zSaveFile); 
         
        orxFILE *file = orxFile_Open(zSaveFile, orxFILE_KU32_FLAG_OPEN_WRITE); 
        orxFile_Print(file, (orxCHAR*)"5561111"); //print score to file     
        orxFile_Close(file); //complete write 
         
        orxFILE *fileToReadBack = orxFile_Open(zSaveFile, orxFILE_KU32_FLAG_OPEN_READ); 
         
        orxSTRING readBackString;  //(orxCHAR*)
        int numRead = orxFile_Read( &readBackString, sizeof(orxCHAR), 7, fileToReadBack    ); 
         
        orxLOG("Read amount %d", numRead);
        orxLOG("Charsize %d", sizeof(orxCHAR));
        orxLOG("As string: %s", readBackString);
    

    I can now read back something using the correct flag of: orxFILE_KU32_FLAG_OPEN_READ but with this fiddling around, I end up either reading memory from somewhere else or crashing.

    I found a good example here: https://bitbucket.org/orx/orx/pull-request/15/update-android-display-plugin-and-demo/diff but it makes use of a struct which it can get the sizeof etc. I just want a simple string (I think).

    I am trying to use the sizeof(orxCHAR) which is a single size version of orxSTRING, and I have 7 chars to read.

    Does anyone have any insight on this?
  • edited November 2014
    I'm glad you found your first problem: opening the file in write mode scraps everything that was already in the file and you can't read any content from it.

    Your second problem comes from your call to orxFile_Read(). You try to store 7 bytes to a pointer that is not initialized (readBackString). It can point anywhere in memory, and that will definitely lead to a crash.

    What you probably want is 8 bytes (1 extra for the null termination) of storage:
    orxCHAR readBackString[8] = {};
    

    Then it should work just fine.

    As a side note, I'd encourage you to use the config system for your save needs. What I do is that I store all my data in properties of a section I usually call "Save". Then I save it to disk with:
    orxConfig_Save(zSaveFile, bEncrypt, SaveCallBack);
    
    // Save Callback
    static orxBOOL orxFASTCALL SaveCallback(const orxSTRING _zSectionName, const orxSTRING _zKeyName, const orxSTRING _zFileName, orxBOOL _bUseEncryption)
    {
      // Return orxTRUE for the section "Save", orxFALSE otherwise
      // -> filters out everything but the "Save" section
      return (orxString_Compare(_zSectionName, "Save") == 0) ? orxTRUE : orxFALSE;
    }
    

    I then reload my save with a simple call to orxConfig_Load(zSaveFile) and I can then access all the data through the config API.
    It has another little bonus as config save/load support encryption (it's basic but good enough for savegames, I think) using a custom key. Just make sure that if you're using a custom key to set it before calling load or save.
  • edited November 2014
    Thank you! Confirmed that orxCHAR readBackString[8] = {}; works. I know it was uninitialised... I also tried: orxSTRING readBackString = "1111111"; but no go.

    And yes, my first preference was to use the orxConfig to push the value back to the config. And this was working for me, however I didn't know how to use the callback as a filter.

    So my entire config (which is fractured in many files) was being pushed out to another file in one big blob.

    Thanks for the example of the callback, this is exactly what I really needed after all.
  • edited November 2014
    Yep, writing over a const string ("11111111") will make the compiler rather unhappy nowadays. ;-)

    For the filter callback, you can filter by whole section or by key.
    Everytime a section will gets serialized, a first call will be made with the section name passed as argument and orxNULL as the key argument. That's where you can reject a full section right away by returning orxFALSE.
    If you return orxTRUE, it'll then ask you again for every single key within the section (this time it'll pass both the section name and the key name when calling the filter). You can now return orxFALSE to reject a single key, or orxTRUE to accept it.

    Of course you can also make a choice based on the encryption parameter (maybe you want to only write if it's encoded or not, I'm not judging ;)), or based on the file name itself (for example you can have a single filter to save to a highscore file and to save the user parameters, and depending on the file name, you'd then allow the "Save" section or the "UserParam" one, for example. Not sure how much of this is relevant to most users, all I can say is that it's available. :)
Sign In or Register to comment.