骑士online源代码[端游源码]是用vc6.0编写的,采用c++/c语言。
使用了完成端口这样通讯方式,并且使用共享内存的交互方式
当然还涉及到sql2000的数据库操作。
开始分析
1.添加Aujard.ini文件及内容
根据网络上下载的要么没有这个文件要么不全,我补充了一下
[ODBC]
ACCOUNT_DSN=KN_online
ACCOUNT_UID=knight
ACCOUNT_PWD=knight
GAME_DSN=KN_online
GAME_UID=knight
GAME_PWD=knight
LOG_DSN=KN_online
LOG_UID=knight
LOG_PWD=knight
[ZONE_INFO]
GROUP_INFO=1
ZONE_INFO=1
2.程序分析
程序的入口是:BOOL CAujardDlg::OnInitDialog()函数,也就是我们主界面的初始化函数,这个函数是创建MFC Dialog界面的时候自 带的,但是主要的功能都在这里做了,所以服务端程序Aujard.exe只需要运行就可以不需要做其他操作就能工作。
下面我们一步一步分析OnInitDialog()函数里面的功能。
//------------------------------------------------------------------
// Logfile initialize 主要是记录运行日志
//-----------------------------------------------------------------
CTime time=CTime::GetCurrentTime();
char strLogFile[50]; memset(strLogFile, 0x00, 50);
wsprintf(strLogFile, "AujardLog-%d-%d-%d.txt", time.GetYear(), time.GetMonth(), time.GetDay());
m_LogFile.Open( strLogFile, CFile::modeWrite | CFile::modeCreate | CFile::modeNoTruncate | CFile::shareDenyNone );
m_LogFile.SeekToEnd();
m_iLogFileDay = time.GetDay();
//------------------------------------------------------------------
// 创建共享内存 需要三块共享内存
// KNIGHT_DB 保存在内存中的玩家数据最大用户3000人,每个用户4000BYTE
// KNIGHT_SEND
// KNIGHT_RECV
// 由于骑士服务端把用户以及物品等相关信息都是保存在内存中的,为了其他游戏的运
// 行速度采取的办法。(至于什么是共享内存,自己去学习吧,这里不作解释。),然
// 后每10秒钟将内存中的玩家信息保存到数据库中,更新数据库。
//-----------------------------------------------------------------
m_LoggerRecvQueue.InitailizeMMF( MAX_PKTSIZE, MAX_COUNT, SMQ_LOGGERSEND, FALSE ); // 分配 Send Queue 虚拟内存共享方式
m_LoggerSendQueue.InitailizeMMF( MAX_PKTSIZE, MAX_COUNT, SMQ_LOGGERRECV, FALSE ); // 分配 Read Queue 虚拟内存共享方式
//初始化用户KNIGHT_DB共享内存
if( !InitializeMMF() ) {
AfxMessageBox("Main Shared Memory Initialize Fail");
AfxPostQuitMessage(0);
return FALSE;
}
//------------------------------------------------------------------
// 读取配置文件Aujard.ini 并初始化数据库,连接数据库,使用CDBAgent类
//------------------------------------------------------------------
CString inipath;
inipath.Format( "%s\\\\Aujard.ini", GetProgPath() );
GetPrivateProfileString( "ODBC", "ACCOUNT_DSN", "", m_strAccountDSN, 24, inipath );
GetPrivateProfileString( "ODBC", "ACCOUNT_UID", "", m_strAccountUID, 24, inipath );
GetPrivateProfileString( "ODBC", "ACCOUNT_PWD", "", m_strAccountPWD, 24, inipath );
GetPrivateProfileString( "ODBC", "GAME_DSN", "", m_strGameDSN, 24, inipath );
GetPrivateProfileString( "ODBC", "GAME_UID", "", m_strGameUID, 24, inipath );
GetPrivateProfileString( "ODBC", "GAME_PWD", "", m_strGamePWD, 24, inipath );
GetPrivateProfileString( "ODBC", "LOG_DSN", "", m_strLogDSN, 24, inipath );
GetPrivateProfileString( "ODBC", "LOG_UID", "", m_strLogUID, 24, inipath );
GetPrivateProfileString( "ODBC", "LOG_PWD", "", m_strLogPWD, 24, inipath );
m_nServerNo = GetPrivateProfileInt("ZONE_INFO", "GROUP_INFO", 1, inipath);
m_nZoneNo = GetPrivateProfileInt("ZONE_INFO", "ZONE_INFO", 1, inipath);
//连接数据库使用CDBAgent类
if( !m_DBAgent.DatabaseInit() ) {
AfxPostQuitMessage(0);
return FALSE;
}
//------------------------------------------------------------------
// 前提:连接上数据库后
// 从数据库中加载ItemTable表保存在m_ItemtableArray队列中
//------------------------------------------------------------------
if( !LoadItemTable() ) {
AfxMessageBox("Load ItemTable Fail!!");
AfxPostQuitMessage(0);
return FALSE;
}
//------------------------------------------------------------------
// 创建定时器
// 三种不同时间的定时器
//------------------------------------------------------------------
SetTimer( PROCESS_CHECK, 40000, NULL );
SetTimer( CONCURRENT_CHECK, 300000, NULL );
SetTimer( PACKET_CHECK, 120000, NULL);
//定时器函数
void CAujardDlg::OnTimer(UINT nIDEvent)
{
HANDLE hProcess = NULL;
switch( nIDEvent ) {
case PROCESS_CHECK:
hProcess = OpenProcess( PROCESS_ALL_ACCESS | PROCESS_VM_READ, FALSE, m_LoggerSendQueue.GetProcessId() );
if( hProcess == NULL )
AllSaveRoutine(); // 如果SendQueue队列执行县城推出了,就保存现在内存中的数据
break;
case CONCURRENT_CHECK:
break;
case SERIAL_TIME:
g_increase_serial = 50001;
break;
case PACKET_CHECK:
WritePacketLog();
break;
}
CDialog::OnTimer(nIDEvent);
}
//------------------------------------------------------------------
//这个函数的主要功能:时刻读取共享内存中的数据(应该是从E文件共享内存中获取
// 来的,他们两个程序共享内存,E文件时主要的通讯文件,接受到客户端的消息后更
// 新内存,而Augard.exe就是直接读取内存,更新数据库),看一下线程函数
// ReadQueueThrea就能明白了
//
//------------------------------------------------------------------
DWORD id;
m_hReadQueueThread = ::CreateThread( NULL, 0, ReadQueueThread, (LPVOID)this, 0, &id);
// ReadQueueThread线程函数
// 这里记录用户登录、删除用户、选择用户。。。
while(TRUE) {
if( pMain->m_LoggerRecvQueue.GetFrontMode() != R ) {
index = 0;
recvlen = pMain->m_LoggerRecvQueue.GetData( recv_buff );
if( recvlen > MAX_PKTSIZE ) {
Sleep(1);
continue;
}
command = GetByte( recv_buff, index );
switch( command ) {
case WIZ_LOGIN:
pMain->AccountLogIn( recv_buff+index );
break;
case WIZ_NEW_CHAR:
pMain->CreateNewChar( recv_buff+index );
break;
case WIZ_DEL_CHAR:
pMain->DeleteChar( recv_buff+index );
break;
case WIZ_SEL_CHAR:
pMain->SelectCharacter( recv_buff+index );
break;
case WIZ_SEL_NATION:
pMain->SelectNation( recv_buff+index );
break;
case WIZ_ALLCHAR_INFO_REQ:
pMain->AllCharInfoReq( recv_buff+index );
break;
case WIZ_LOGOUT:
pMain->UserLogOut( recv_buff+index );
break;
case WIZ_DATASAVE:
pMain->UserDataSave( recv_buff+index );
break;
case WIZ_KNIGHTS_PROCESS:
pMain->KnightsPacket( recv_buff+index );
break;
case WIZ_CLAN_PROCESS:
pMain->KnightsPacket( recv_buff+index );
break;
case WIZ_LOGIN_INFO:
pMain->SetLogInInfo( recv_buff+index );
break;
case WIZ_KICKOUT:
pMain->UserKickOut( recv_buff+index );
break;
case WIZ_BATTLE_EVENT:
pMain->BattleEventResult( recv_buff+index );
break;
case DB_COUPON_EVENT:
pMain->CouponEvent( recv_buff+index );
break;
}
recvlen = 0;
memset( recv_buff, NULL, 1024 );
}
}
Aujard.exe就分析到这里,至于里面的具体实现
大家还是自己看看吧,这里有我以前分享的骑士online源码资源。
我在这里只是把功能结构给大家分析,以便大家更好研究。
下载声明:
1、本站所有资源、仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考, 不提供任何技术服务。
2、本站资源均有第三方用户自行上传分享推荐,非本站自制,仅供玩家做交流学习之用!切勿用于商业用途!游戏作品版权
归原作者享有,如有版权问题,请附带版权证明至邮件,本平台将应您的要求删除。举报邮箱 :859840003@qq.com
评论