Database for MMORPG
Database for MMORPG
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 !!!
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 !!!
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/
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
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
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.
So you want to make a MMORPG
Why your next MMORPG will fail
"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.
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:CuteAlien wrote:Here's an article with some recommendation for that and other topics about mmorpg's: http://www.devmaster.net/articles/building-mmorpg/
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
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
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
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
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
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;
}
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
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?
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?
Compete or join in irrlichts monthly screenshot competition!
Blog/site: http://rex.4vandorp.eu
Company: http://www.islandworks.eu/, InCourse
Twitter: @strong99
Blog/site: http://rex.4vandorp.eu
Company: http://www.islandworks.eu/, InCourse
Twitter: @strong99
can't tell you about my work since it is something that needs to be protected.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
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.
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: that are better to use with irrlicht engine for building the database?
yes, see soap or webservices for more details. best for sending and receiving user-related data, not game state data.henryhks wrote: Is it good to use xml as data transfer?
Thanks all again!!
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.
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
Yawwwwwwwwwwn. Sorry, did you say something? I drifted off for a second there.dlangdev wrote:can't tell you about my work since it is something that needs to be protected.
What's the benefit of using soap rather than a custom scheme sent via TCP?dlangdev wrote:some tools you probably should look into:
1) soap: use this pipe [...]
What's a "UDP stream"?dlangdev wrote:2) udp/tcp streams:
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
hi rogerborg,rogerborg wrote:Yawwwwwwwwwwn. Sorry, did you say something? I drifted off for a second there.dlangdev wrote:can't tell you about my work since it is something that needs to be protected.
What's the benefit of using soap rather than a custom scheme sent via TCP?dlangdev wrote:some tools you probably should look into:
1) soap: use this pipe [...]
What's a "UDP stream"?dlangdev wrote:2) udp/tcp streams:
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.
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
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
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
-
- Posts: 5
- Joined: Thu Jan 31, 2008 7:37 pm
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...strong99 wrote: Isn't a small MMORPG a SMORPG?
Small Multiplayer Online Role Playing game?