Pages: [1]
  Print  
Author Topic: Save Files  (Read 1010 times)
XLambda
Swordsman
***
Posts: 22


View Profile
« on: January 31, 2012, 10:58:16 PM »

I've been thinking about doing a little c++ project with libtcod for this year's 7drl. My main problem with the language, though, is the implementation of save files. In Java, I can easily serialize large data structures without breaking a sweat. In c++ though, I seem to be stuck with manually streaming every single primitive to a file. Is there no more elegant way to do this? I thought I might ask around here, since I personally have very little experience with c++ file I/O.
Logged
jice
Administrator
Master
*****
Posts: 1455


View Profile WWW
« Reply #1 on: February 05, 2012, 12:44:57 AM »

I think boost has some serialization stuff :
http://www.boost.org/doc/libs/1_49_0_beta1/libs/serialization/doc/index.html
Logged
will
Warder
*
Posts: 99


View Profile WWW
« Reply #2 on: March 06, 2012, 06:26:49 PM »

I've been using Sqlite3. I dump the whole class as a blob into the db with an ownerid(client session ID) as the table index . It was actually easy to build a DLL and lib from the source. http://www.sqlite.org/download.html.

Works better than I expected. I've been using this to store user's entities in the legacy of a warlord server. Using transactions you can get 50 to 100 thousand class blobs into the DB in a few seconds.

I'll post some code soon as I can access my dev system. I was amazed it took about half the lines of code to write a SQLite DB class wrapper. This is compared to a class that accessed an XML document (in about 1/3 the development time). I'm actually refactoring now to have everything use SQLite3.

Will

Logged
will
Warder
*
Posts: 99


View Profile WWW
« Reply #3 on: March 07, 2012, 07:21:53 AM »

Copy and paste from what I currently use. Edit: forgot to post how to get data in.

put into database
Code:
bool EntityFactory::saveEntitiesDB3(std::string str) {
    sqlite3 * db = NULL;
    int result = 0;

    result = sqlite3_open(str.data(), &db);

    if (result != SQLITE_OK) {
        sqlite3_close(db);
        return false;
    }

    bool dbClean = true;
    sqlite3_stmt *pStmt = NULL;

    result = sqlite3_exec(db, "DELETE FROM entities;", NULL, NULL, NULL); // clear out old save data
    result = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL); // begin a transaction for efficiency and speed

    std::string sqlTxt("INSERT INTO entities (ownerid,type,skills) VALUES (?1,?2,?3)");
    result = sqlite3_prepare_v2(db, sqlTxt.data(), sqlTxt.size(), &pStmt, NULL);
    if (result == SQLITE_OK && pStmt) {

        std::vector<Entity*>::iterator vitEntity = Entities.begin();
        Entity * pE = NULL;
        std::string const * eName = NULL;
        std::vector<Skill> const * vSkills = NULL;

        while (vitEntity != Entities.end()) {
            pE = (*vitEntity++); // point to the entity(npc/pc) in the list
            // bind all the variables into the above SQL statement
            sqlite3_bind_int(pStmt, 1, pE->getID());
            eName = pE->getTypeName();
            sqlite3_bind_text(pStmt, 2, eName->data(), eName->size(), NULL);
            vSkills = pE->getSkillsList();
            std::size_t size = vSkills->size() * sizeof (Skill);
            sqlite3_bind_blob(pStmt, 3, vSkills->data(), size, SQLITE_STATIC); // sqlite_static is important, so object is not destructed!
            sqlite3_step(pStmt);
            sqlite3_reset(pStmt);
        }

    } else {
        dbClean = false;
    }

    result = sqlite3_finalize(pStmt);
    if (dbClean) result = sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL); // commits transaction if clean
    sqlite3_close(db);
    return dbClean;
}

read from database
Code:
bool EntityFactory::loadEntitiesFromDB(std::string str) {
    sqlite3 * db = NULL;
    int result = 0;
    result = sqlite3_open(str.data(), &db);

    if (result != SQLITE_OK) {
        sqlite3_close(db);
        return false;
    }

    bool dbClean = true;
    std::string sqlTxt("SELECT ownerid,typename,skills FROM entities;");
    sqlite3_stmt *pStmt = NULL;

    result = sqlite3_prepare_v2(db, sqlTxt.data(), sqlTxt.size(), &pStmt, NULL);
    if (result == SQLITE_OK && pStmt) {
        while (sqlite3_step(pStmt) == SQLITE_ROW) {
           /// grab values from rowset here
            int i = sqlite3_column_int(pStmt, 0);
            std::string str(reinterpret_cast<const char*> (sqlite3_column_text(pStmt, 1)));
            
            // point at the beginning of the data blob with a class pointer.
            //  skill in this case.
            Skill const * pSK = (Skill const*) sqlite3_column_blob(pStmt, 2);
            
            // grab blob size. It was
            int size = sqlite3_column_bytes(pStmt, 2);
            
            // create vector using pointer and memory size,
            //    it is smart enough to chop up the blob into bite size classes
            std::vector<Skill> vSkills(pSK, pSK + size);
            
            // create new entity from save information,
            //  tosses into entity list when done.
            createEntity(str, i, vSkills);
        }
    } else {
        dbClean = false;
    }

    sqlite3_finalize(pStmt);
    sqlite3_close(db);
    return dbClean;
}

If you need the compiled library and libs, I have a copy on bitbucket. https://bitbucket.org/willraman/legacy-of-a-warlord-client/
I'd recommend getting the source from the source though, http://www.sqlite.org/download.html
« Last Edit: March 09, 2012, 08:38:40 PM by will » Logged
Pages: [1]
  Print  
 
Jump to: