Database for MMORPG

Post your questions, suggestions and experiences regarding game design, integration of external libraries here. For irrEdit, irrXML and irrKlang, see the
ambiera forums
henryhks
Posts: 2
Joined: Sat Jan 19, 2008 5:03 pm

Database for MMORPG

Post by henryhks »

Hi all, My team is building a small MMORPG using irrlicht Engine.

we would like to build our data storage based on xml.

Is it a bad idea? Since xml does not support multi-user...

we do not have much experience on database programming

can anyone give us some suggestion? Thanks all !!!
CuteAlien
Admin
Posts: 9736
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

It's simply impossible to give a general answer to that. In some cases it will be a good idea in other it will be a horrible idea.

Here's an article with some recommendation for that and other topics about mmorpg's: http://www.devmaster.net/articles/building-mmorpg/
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Yoran
Site Admin
Posts: 96
Joined: Fri Oct 07, 2005 8:55 am
Location: The Netherlands
Contact:

Post by Yoran »

For storing information clientside XML can be fast and reusable.
For storing information serverside for so many users in a MMORPG you really need a good fast database like MySQL using InnoDB storage engine for transactions.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Oh dear, another "small M[assive]MORPG".

"xml" is a general purpose markup language. It has no relationship to whether your environment is multi-user or otherwise. What matters is that you are able to achieve fast, reliable and synchronised access to the database, not its scheme.

Constructively, I'd suggest that you go with whatever Worldforge uses. Actually, just use Worldforge. There's hundreds of man years of work in that project, all there waiting for you.
CuteAlien wrote:Here's an article with some recommendation for that and other topics about mmorpg's: http://www.devmaster.net/articles/building-mmorpg/
That's a pretty good article, and I'm largely in agreement with his conclusions, even with the suggestion that a raw filesystem is a viable alternative to a RDB (at least for a "small massive" ;) ). However, I'm not sure that it really captures the full scope of what's required, so I'd also recommend these:

So you want to make a MMORPG

Why your next MMORPG will fail
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
henryhks
Posts: 2
Joined: Sat Jan 19, 2008 5:03 pm

Post by henryhks »

Thanks for reply!!

The articles are quite good for me~

Now I am going to build the database.

Can anyone one suggest some softares, tools, etc

that are better to use with irrlicht engine for building the database?

Is it good to use xml as data transfer?

Thanks all again!!
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

henryhks wrote:Can anyone one suggest some softares, tools, etc that are better to use with irrlicht engine for building the database?
Yoran wrote:For storing information serverside for so many users in a MMORPG you really need a good fast database like MySQL using InnoDB storage engine for transactions.

henryhks wrote:Is it good to use xml as data transfer?
CuteAlien wrote:It's simply impossible to give a general answer to that. In some cases it will be a good idea in other it will be a horrible idea.
Yoran wrote:For storing information clientside XML can be fast and reusable.
Rogerborg wrote:What matters is that you are able to achieve fast, reliable and synchronised access to the database, not its scheme.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
drac_gd
Posts: 132
Joined: Sun Apr 09, 2006 8:43 pm

Post by drac_gd »

Sqlite is a good database for most games. Small fast and free for any use licence. For massive RPG server you would probably need a expensive solution like oracal etc.
In any case I like Sqlite. add 2 files to your project and you have a SQL database.

[/code]http://www.sqlite.org/

Here is some code from some stuff I am coding

Code: Select all

#pragma once
//============================================================================
// Copyright (C) 2003-2008 Brett R. Jones 
// All Rights Reserved
//
// You may redistribute and/or modify for non commercial and commercial uses 
// provided this copyright notice remains in place and is not modified
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// brett.r.jones@gmail.com
// http://www.tronacom.com    http://www.slytron.com
//============================================================================


class DbBase
{
public:
	//=== constructor ===//
	DbBase();
	//=== destructor ===//
	~DbBase();

	//! Initialize the database
	virtual RCODE DbStartup( const TCHAR * pDbFileName );
	//! shutdown the database
	virtual RCODE DbShutdown( void );

	//! open the database
	virtual RCODE DbOpen( void );
	//! close the database
	virtual RCODE DbClose( void );


	//! create initial database
	virtual RCODE DbCreateDatabase( void );
	//! create initial tables in the database
	virtual RCODE DbCreateTables( void ) = 0;

	//! archive database into given directory
	virtual RCODE DbArchive( const TCHAR * pArchiveDirectory, BOOL bClearExistingDb = false );

	//! execute Sql statement
	virtual RCODE SqlExec( TCHAR * pSqlStatment );
	//! execute Sql statement
	virtual RCODE SqlExec( const TCHAR * pSqlString, ... );


	//=== vars ===//
	TCHAR		m_atcDbFileName[ MAX_PATH ];
    sqlite3 *	m_pDb;
	BOOL		m_bDbInitialized; // if true database initialized

};

Code: Select all

//============================================================================
// Copyright (C) 2003-2008 Brett R. Jones 
// All Rights Reserved
//
// You may redistribute and/or modify for non commercial and commercial uses 
// provided this copyright notice remains in place and is not modified
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// brett.r.jones@gmail.com
// http://www.tronacom.com    http://www.slytron.com
//============================================================================

#include "stdafx.h"
#include "VxUtilLib.h"


//---------------------------------------------------------------------------
//=== constructor ===//
DbBase::DbBase() :
	  m_bDbInitialized(0)
	, m_pDb(0)
{
	m_atcDbFileName[0] = 0;
}
//---------------------------------------------------------------------------
//=== destructor ===//
DbBase::~DbBase()
{
}

//---------------------------------------------------------------------------
//! Initialize the database
RCODE DbBase::DbStartup( const TCHAR * pDbName )
{
	RCODE rc = 0;
    char tmpDir[ MAX_PATH ];
    char* pTemp;

	vx_assert( pDbName );
	if( pDbName[1] != ':' )
	{
		// we need full path to database file name
		 rc = VxGetExecuteDirectory( m_atcDbFileName, sizeof( m_atcDbFileName ) );
		 if( rc )
		 {
		    log_msg( 0, "DbBase: error %d getting execute path\n", rc );
			return rc;
		 }
		 strcat( m_atcDbFileName, pDbName );
	}
	else
	{
		// was given full path
		strcpy(m_atcDbFileName, pDbName );
	}
        
    // create paths and database if neccesary
    if( ! VxFileExists(m_atcDbFileName) )
    {
        //create db 
        strcpy( tmpDir, m_atcDbFileName );
        pTemp = strrchr( tmpDir, '/' );
        if( NULL == pTemp )
        {
		    log_msg( 0, "DbBase: error creating database directory\n" );
		}
        pTemp[0] = '\0';
        VxMakeDirectory( tmpDir );
      
        rc = DbCreateDatabase();
        if( 0 != rc )
        {
            log_msg( 0,"DbBase:Cannot create database %s\n", m_atcDbFileName);
            return rc;
        }
    }
    m_bDbInitialized = TRUE;
    log_msg( 0, "DbBase: %s initialized\n", m_atcDbFileName );
    return 0;

}

//---------------------------------------------------------------------------
//! shutdown the database
RCODE DbBase::DbShutdown( void )
{
	return 0;
}
//---------------------------------------------------------------------------
//! archive database into given directory
RCODE DbBase::DbArchive( const TCHAR * pArchiveDirectory, BOOL bClearExistingDb )
{
	/*
	char ArchiveDir[MAX_PATH];
	char ArchiveDbPath[MAX_PATH];
	
	if (!g_bAcctDbInitialized)
	{
		if(0 != StartupAcctDb(DEFAULT_EXEC_PATH))
		{
			log_msg(SRV_DB_ACCT_ERR, "ArchiveDay:Storage Failed to Init\n");
			return -1;
		}
	}
	sprintf(ArchiveDir, "%s%s", g_atcAcctDbExecPath, DEFAULT_ACCT_ARCHIVE_DIR);
	if(0 != VxMakeDirectory(ArchiveDir))
	{
		log_msg(SRV_DB_ACCT_ERR,"ArchiveDay:Cannot create archive directory %s\n", ArchiveDir);
		return -1;
	}
	char TimeStamp[100];
	VxGetTimeStamp(TimeStamp, 100);
	sprintf(ArchiveDbPath, "%s%sacct_db%s", g_atcAcctDbExecPath, DEFAULT_ACCT_ARCHIVE_DIR, TimeStamp);
	if ( 0 == (VxCopyFile( g_atcAcctDbPath, ArchiveDbPath )))
	{
		VxDeleteFile( g_atcAcctDbPath );
	}
	else
	{
		log_msg(SRV_DB_ACCT_ERR, "AchiveAcctDb:Error copying db file\n");
		return -1;
	}
	if(0 != StartupAcctDb(g_atcAcctDbExecPath))
	{
		log_msg(SRV_DB_ACCT_ERR, "ArchiveAcctDb:Storage Failed to Init New Db\n");
		return -1;
	}
	*/
	return 0;	
}

//---------------------------------------------------------------------------
//! create initial database
RCODE DbBase::DbCreateDatabase( void )
{
	sqlite3 *db;
    int retval;
	RCODE rc;
    
    retval = sqlite3_open(m_atcDbFileName, &db);
    if (!(SQLITE_OK == retval))
    {
        log_msg(SRV_DB_ACCT_ERR,"DbCreateDatabase:Unable to open databse %s\n",m_atcDbFileName);
        sqlite3_close(db);
        return -1;
    }
    // close database.. Create tables will reopen
    sqlite3_close(db);
    // make tables in database
    rc = DbCreateTables();
	if( rc )
    {
        log_msg(SRV_DB_ACCT_ERR,"CreateDataBase:Unable to create AcctTable in db %s\n",m_atcDbFileName);
    }
    return rc;
}

//---------------------------------------------------------------------------
//! create initial tables in the database
RCODE DbBase::DbCreateTables( void )
{

	return 0;
}
//---------------------------------------------------------------------------
//! open the database
RCODE DbBase::DbOpen( void )
{
    int retval;
    retval = sqlite3_open( m_atcDbFileName, &m_pDb );
    if (!(SQLITE_OK == retval))
    {
        log_msg( 0, "DbBase:Unable to open db %s\n", m_atcDbFileName);
        sqlite3_close(m_pDb);
		m_pDb = NULL;
        return -1;
    }
	return 0;
}
//---------------------------------------------------------------------------
//! close the database
RCODE DbBase::DbClose( void )
{
	if( m_pDb )
	{
        sqlite3_close(m_pDb);
		m_pDb = NULL;
		return 0;
	}
    log_msg( 0, "DbBase:Tried to close allready closed db %s\n", m_atcDbFileName);
	return -1;
}

//---------------------------------------------------------------------------
//! execute Sql statement
RCODE DbBase::SqlExec( const TCHAR * pSqlString, ... )
{
    char SQL_Statement[65535];

	va_list arg_ptr;
	va_start(arg_ptr, pSqlString);
	vsprintf(SQL_Statement, pSqlString, (TCHAR *) arg_ptr);
	va_end(arg_ptr);
	return SqlExec( SQL_Statement );
}

//---------------------------------------------------------------------------
//! execute Sql statement
RCODE DbBase::SqlExec( TCHAR * SQL_Statement )
{
    char *SQL_Error;
    int retval;
	RCODE rc;

	rc = DbOpen();
	if( 0 == rc )
	{
		retval = sqlite3_exec( m_pDb, SQL_Statement, NULL, NULL, &SQL_Error );
		if (!(SQLITE_OK == retval))
		{
			log_msg( 0, "DbBase:sqlite3_exec:%s", SQL_Error );
			sqlite3_free(SQL_Error);
			DbClose();
			return -1;
		}
	}
	rc = DbClose();
    return rc;
}

Code: Select all

#pragma once
//============================================================================
// Copyright (C) 2003-2008 Brett R. Jones 
// All Rights Reserved
//
// You may redistribute and/or modify for non commercial and commercial uses 
// provided this copyright notice remains in place and is not modified
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// brett.r.jones@gmail.com
// http://www.tronacom.com    http://www.slytron.com
//============================================================================


#define DEFAULT_ACCT_DATABASE_FILE "database/drac_acct_db.dbw"

// forward declare
class UserAcctInfo;

class DbAcct : public DbBase
{
public:
	//=== constructor ===//
	DbAcct();
	//=== destructor ===//
	~DbAcct();

	//! create initial tables in the database
	RCODE DbCreateTables( void );

	//! query account using login name
	RCODE QueryUserAcct(	const TCHAR *	pLoginName,
							UserAcctInfo *	poRetUserAcctInfo );
	//! query account using account id
	RCODE QueryUserAcct(	U32				u32AcctId,
							UserAcctInfo *	poRetUserAcctInfo );
	//! query all accounts in the database.. NOTE: caller must delete the returned UserAcctInfo pointers in the list
	RCODE QueryAllAccts( VxList * poRetList );

	//! update users account in database 
	RCODE UpdateUser( UserAcctInfo * poUserAcct );
	//! add user to account database 
	RCODE AddUser( UserAcctInfo * poUserAcct );

	//! remove users account from database 
	RCODE RemoveUser( UserAcctInfo * poUserAcct );

protected:
	//! query user account
	RCODE SqlQueryUserAcct( char * SQL_Statement, UserAcctInfo * pRetUserAcctInfo );


};

Code: Select all

//============================================================================
// Copyright (C) 2003-2008 Brett R. Jones 
// All Rights Reserved
//
// You may redistribute and/or modify for non commercial and commercial uses 
// provided this copyright notice remains in place and is not modified
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// brett.r.jones@gmail.com
// http://www.tronacom.com    http://www.slytron.com
//============================================================================

#include "stdafx.h"
#include "SlytronSrvAll.h"



//---------------------------------------------------------------------------
//=== constructor ===//
DbAcct::DbAcct()
{
}
//---------------------------------------------------------------------------
//=== destructor ===//
DbAcct::~DbAcct()
{
}
//---------------------------------------------------------------------------
//! create initial tables in the database
RCODE DbAcct::DbCreateTables( void )
{
    char SQL_Statement[65535];
    
    sprintf(SQL_Statement, "CREATE TABLE UserAcct (AcctId INTEGER, LoginName TEXT, Object BLOB)");

	return SqlExec( SQL_Statement );
}
//---------------------------------------------------------------------------
//! query user account
RCODE DbAcct::SqlQueryUserAcct( char * SQL_Statement, UserAcctInfo * pRetUserAcctInfo )
{
	RCODE rc;
	

    char *SQL_Error = NULL;
    size_t retval;
    sqlite3_stmt *pPreparedStatement;

	rc = DbOpen();
	if( rc )
	{
		return rc;
	}   
    retval = sqlite3_prepare( m_pDb, SQL_Statement,(int)strlen(SQL_Statement),&pPreparedStatement,NULL);  
    if (!(SQLITE_OK == retval))
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"GetUserAcct:sqlite3_prepare:%s\n",SQL_Error);
		DbClose();
        return -1;
    }
    while(!(SQLITE_DONE == (retval = sqlite3_step(pPreparedStatement))))
    {
        if ((SQLITE_ERROR == retval) || (SQLITE_MISUSE == retval))
        {
            //error
            SQL_Error = (char*) sqlite3_errmsg(m_pDb);
            log_msg(SRV_DB_ACCT_ERR,"GetUserAcct:sqlite3_step:%s\n",SQL_Error);
            sqlite3_finalize(pPreparedStatement);
			DbClose();
            return -1;
        }
        else if(SQLITE_ROW == retval)
        {
            //got a row
			UserAcctInfo *pUserAcctInfoIn;
            pUserAcctInfoIn = (UserAcctInfo*) sqlite3_column_blob(pPreparedStatement,0);
            if( NULL == pUserAcctInfoIn )
            {
                //error
                SQL_Error = (char*) sqlite3_errmsg(m_pDb);
                log_msg(SRV_DB_ACCT_ERR,"GetUserAcct:sqlite3_column_blob:%s\n",SQL_Error);                
                sqlite3_finalize(pPreparedStatement);
				DbClose();
                return -1;
            }
            memcpy( pRetUserAcctInfo, pUserAcctInfoIn, sizeof(UserAcctInfo) );
		    sqlite3_finalize(pPreparedStatement);
			DbClose();
			return 0;
        }
        else
        {
            // SQLITE_BUSY just continue
            log_msg(SRV_DB_ACCT_DBG, "UserAcctInfo:Recieved SQLITE_BUSY\n");
        }
    }
	// not fount
    sqlite3_finalize(pPreparedStatement);
	DbClose();
	return -1;
}

//---------------------------------------------------------------------------
//! query account using login name
RCODE DbAcct::QueryUserAcct(	const TCHAR * pLoginName,
								UserAcctInfo * poRetUserAcctInfo )
{
    char SQL_Statement[65535];
    sprintf(SQL_Statement,"SELECT Object FROM UserAcct WHERE LoginName = '%s'",
         pLoginName );
	return SqlQueryUserAcct( SQL_Statement, poRetUserAcctInfo );
}
//---------------------------------------------------------------------------
//! query account using account id
RCODE DbAcct::QueryUserAcct(	U32				u32AcctId,
								UserAcctInfo *	poRetUserAcctInfo )
{
    char SQL_Statement[65535];
    sprintf(SQL_Statement,"SELECT Object FROM UserAcct WHERE AcctId = %d",
								u32AcctId );
	return SqlQueryUserAcct( SQL_Statement, poRetUserAcctInfo );
}

//---------------------------------------------------------------------------
//! query all accounts in the database.. NOTE: caller must delete the returned UserAcctInfo pointers in the list
RCODE DbAcct::QueryAllAccts( VxList * poRetList )
{

    char *SQL_Error = NULL;
    size_t retval;
    sqlite3_stmt *pPreparedStatement;
    char SQL_Statement[1024];
    sprintf(SQL_Statement,"SELECT Object FROM UserAcct");
    
	RCODE rc = DbOpen();
	if( rc )
	{
		return rc;
	}   
   
    retval = sqlite3_prepare(m_pDb, SQL_Statement,(int)strlen(SQL_Statement),&pPreparedStatement,NULL);  
    if (!(SQLITE_OK == retval))
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"QueryAllAccts:sqlite3_prepare:%s\n",SQL_Error);
		DbClose();
        return -1;
    }

    while(!(SQLITE_DONE == (retval = sqlite3_step(pPreparedStatement))))
    {
        if ((SQLITE_ERROR == retval) || (SQLITE_MISUSE == retval))
        {
            //error
            SQL_Error = (char*) sqlite3_errmsg(m_pDb);
            log_msg(SRV_DB_ACCT_ERR,"QueryAllAccts:sqlite3_step:%s\n",SQL_Error);
            sqlite3_finalize(pPreparedStatement);
			DbClose();
            return -1;
        }
        else if(SQLITE_ROW == retval)
        {
            //got a row
			UserAcctInfo *poUserAcctTemp;
            poUserAcctTemp = (UserAcctInfo*) sqlite3_column_blob(pPreparedStatement,0);
            if( NULL == poUserAcctTemp )
            {
                //error
                SQL_Error = (char*) sqlite3_errmsg(m_pDb);
                log_msg(SRV_DB_ACCT_ERR,"QueryAllAccts:sqlite3_column_blob:%s\n",SQL_Error);                
                sqlite3_finalize(pPreparedStatement);
				DbClose();
                return -1;
            }
			// make a copy and add to the list
			UserAcctInfo *	poUserAcct = new UserAcctInfo();
			memcpy( poUserAcct, poUserAcctTemp, sizeof( UserAcctInfo ) );
			poRetList->AddTailNode( poUserAcct );
        }
        else
        {
            //SQLITE_BUSY just continue
            log_msg(SRV_DB_ACCT_DBG, "UserAcctInfo:Recieved SQLITE_BUSY\n");
        }
    }
    sqlite3_finalize(pPreparedStatement);
	DbClose();
	return 0;
}
//---------------------------------------------------------------------------
//! update users account in database 
RCODE DbAcct::UpdateUser( UserAcctInfo * poUserAcct )
{
//	RemoveUser( poUserAcct );
//	return AddUser( poUserAcct );
	
    char SQL_Statement[65535];
    char *SQL_Error;
	int retval;
    sqlite3_stmt *pStatement;   //pointer to prepared statement
	RCODE rc = DbOpen();
	if( rc )
	{
		return rc;
	}
    //next insert new data
    sprintf(SQL_Statement,"UPDATE UserAcct SET Object = ? WHERE AcctId = %d", 
							poUserAcct->m_u32AcctId );
	int iLen = (int)strlen( SQL_Statement );
    vx_assert( iLen > 0 && iLen < sizeof( SQL_Statement ) );
    retval = sqlite3_prepare(m_pDb,SQL_Statement,(int)strlen(SQL_Statement),&pStatement, NULL);
    if (!(SQLITE_OK == retval))
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"AcctDbUpdateUser:sqlite3_prepare:%s\n",SQL_Error);
		DbClose();
        return -1;
    }

    retval = sqlite3_bind_blob(pStatement,1,poUserAcct,sizeof(UserAcctInfo),SQLITE_TRANSIENT);
    if (!(SQLITE_OK == retval))
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"AcctDbUpdateUser:sqlite3_bind_blob:%s\n",SQL_Error);
        sqlite3_finalize(pStatement);
		DbClose();
        return -1;
    }

    retval = sqlite3_step(pStatement);
    if (SQLITE_ERROR == retval)
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"AcctDbUpdateUser:sqlite3_step:%s\n",SQL_Error);
        sqlite3_finalize(pStatement);
		DbClose();
        return -1;
    }
    sqlite3_finalize(pStatement);
	DbClose();
	return 0;
	
}

//---------------------------------------------------------------------------
//! add user to account database 
RCODE DbAcct::AddUser( UserAcctInfo * poUserAcct )
{
    char SQL_Statement[65535];
    char *SQL_Error;
	int retval;
    sqlite3_stmt *pStatement;   //pointer to prepared statement
	RCODE rc = DbOpen();
	if( rc )
	{
		return rc;
	}
    //next insert new data
    sprintf(SQL_Statement,"INSERT INTO UserAcct (AcctId, LoginName, Object) VALUES (%d,'%s',?)", 
							poUserAcct->m_u32AcctId,
							poUserAcct->m_atcLoginName );
	int iLen = (int)strlen( SQL_Statement );
    vx_assert( iLen > 0 && iLen < sizeof( SQL_Statement ) );
    retval = sqlite3_prepare(m_pDb,SQL_Statement,(int)strlen(SQL_Statement),&pStatement, NULL);
    if (!(SQLITE_OK == retval))
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"AcctDbAddUser:sqlite3_prepare:%s\n",SQL_Error);
		DbClose();
        return -1;
    }

    retval = sqlite3_bind_blob(pStatement,1,poUserAcct,sizeof(UserAcctInfo),SQLITE_TRANSIENT);
    if (!(SQLITE_OK == retval))
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"AcctDbAddUser:sqlite3_bind_blob:%s\n",SQL_Error);
        sqlite3_finalize(pStatement);
		DbClose();
        return -1;
    }

    retval = sqlite3_step(pStatement);
    if (SQLITE_ERROR == retval)
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"AcctDbAddUser:sqlite3_step:%s\n",SQL_Error);
        sqlite3_finalize(pStatement);
		DbClose();
        return -1;
    }
    sqlite3_finalize(pStatement);
	DbClose();
	return 0;
}
//---------------------------------------------------------------------------
//! remove users account from database 
RCODE DbAcct::RemoveUser( UserAcctInfo * poUserAcct )
{
    char SQL_Statement[65535];
    char *SQL_Error;
	int retval;
	RCODE rc = DbOpen();
	if( rc )
	{
		return rc;
	}
		
    //delete user
    sqlite3_exec( m_pDb,"BEGIN",NULL,NULL,NULL);
    sprintf(SQL_Statement,"DELETE FROM UserAcct WHERE AcctId = %d",
									poUserAcct->m_u32AcctId );
    retval = sqlite3_exec(m_pDb,SQL_Statement,NULL, NULL, &SQL_Error);
    if (!(SQLITE_OK == retval))
    {
        SQL_Error = (char*) sqlite3_errmsg(m_pDb);
        log_msg(SRV_DB_ACCT_ERR,"AcctDb RemoveUser:sqlite3_exec:%s\n",SQL_Error);
		DbClose();
        return -1;
    }
	DbClose();
	return 0;
}
dejai
Posts: 522
Joined: Sat Apr 21, 2007 9:00 am

Post by dejai »

The WoW Database uploads player information every 4 nanoseconds. Thats about all the light I can shed on the issue.
Programming Blog: http://www.uberwolf.com
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Hmm, where would it upload the data that fast. I guess there's no net infrastructure which could handle that speed. So it's at most from disk to RAM, but the latter will fill up pretty fast...
Strong99
Admin
Posts: 687
Joined: Fri Mar 31, 2006 7:06 pm
Location: Netherlands
Contact:

Post by Strong99 »

They use multiple database servers, one to store player data, one to store other, you get better preformence but 4 nanoseconds is indeed very low...
but maybe they even have the player data database seperated...

and making arrays of disks for 1 table will improves speed very good. Its the same as a raid disk setup. Though you need special database structures to achieve that

@ Dejai
Wich database structure do they use than?

@ henryhks
Isn't a small MMORPG a SMORPG?
Small Multiplayer Online Role Playing game?
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

henryhks wrote:Thanks for reply!!

The articles are quite good for me~

Now I am going to build the database.

Can anyone one suggest some softares, tools, etc
can't tell you about my work since it is something that needs to be protected.

some tools you probably should look into:

1) soap: use this pipe to send/receive data that is not time sensitive, response time can be half second to five seconds. you can place your database related data on this pipe, for example: login, score, etc.

2) udp/tcp streams: use this protocol when response time is critical. game synch is one of them. for example: raknet, irrnet, enet, torque net, etc.



henryhks wrote: that are better to use with irrlicht engine for building the database?
just use a soap api/library, slap it onto the irrlicht client game program. soap should connect to a webservice which connect to a database server.

henryhks wrote: Is it good to use xml as data transfer?

Thanks all again!!
yes, see soap or webservices for more details. best for sending and receiving user-related data, not game state data.

no, don't use soap for game synch. soap is slow for synching player state across the net.

====================

by the way, the one i wrote is no bullshit. that's the design i'm going to implement for my project.

the scene editor i'm currently cobbling-up will run on two platforms: desktop standalone and server multiuser. i have a design already in place that i'm simply implementing each of those design spec one bit at a time.
Image
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

dlangdev wrote:can't tell you about my work since it is something that needs to be protected.
Yawwwwwwwwwwn. Sorry, did you say something? I drifted off for a second there.


dlangdev wrote:some tools you probably should look into:

1) soap: use this pipe [...]
What's the benefit of using soap rather than a custom scheme sent via TCP?

dlangdev wrote:2) udp/tcp streams:
What's a "UDP stream"?
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

rogerborg wrote:
dlangdev wrote:can't tell you about my work since it is something that needs to be protected.
Yawwwwwwwwwwn. Sorry, did you say something? I drifted off for a second there.


dlangdev wrote:some tools you probably should look into:

1) soap: use this pipe [...]
What's the benefit of using soap rather than a custom scheme sent via TCP?

dlangdev wrote:2) udp/tcp streams:
What's a "UDP stream"?
hi rogerborg,

the first one was a comment designed to provoke response like that, so you took the bait.

anyway, keep up the good work.

please correct my mistakes for me. really appreciate them.
Image
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

I am genuinely interested in the suggestion to use soap in addition to an IP based scheme. What's the thinking behind that?
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
HighTreason
Posts: 5
Joined: Thu Jan 31, 2008 7:37 pm

Post by HighTreason »

strong99 wrote: Isn't a small MMORPG a SMORPG?
Small Multiplayer Online Role Playing game?
Well, since MMORPG actually stands for "Massively Multiplayer Online Roleplaying Game," he could mean that it is small in some way other than the number of players that can log in at once. For instance, he could be creating an MMORPG with a small world or with very few features, etc. You never know...
Post Reply