• HyperFilter | DoS Protection | DDoS Protection | DoS Mitigation | DDoS Mitigation | AntiDoS | AntiDDoS | Proxy Shielding

Ajuard'ın oyun içindeki yaptıgı işlemler

  • Konbuyu başlatan Konbuyu başlatan HiFi
  • Başlangıç tarihi Başlangıç tarihi

HiFi

Kayıtlı Üye
Katılım
9 Mart 2012
Mesajlar
575
AI Serverın oluşturduğu map bilgilerini alıyor.Bu maplar dosyaların çalıştığı bilgisayarda paylaşılan hafıza ( shared memory ) olarak geçiyor ve bütün dosyalar tarafından kullanabilir olarak açılıyor.







Kod:
 if( bCreate )         m_hMMFile = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, dwfullsize, lpname );     else         m_hMMFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, TRUE, lpname );          if( m_hMMFile == NULL ) {         strcpy( logstr , "Shared Memory Open Fail!!\r\n" );         LogFileWrite( logstr );         return FALSE;     }
AI Server dosyaları yüklememişse,yüklüyor.Yüklenmiş ise yüklü bilgileri almayı deniyor.Eğer onuda yapamazsa Shared Memory Open Fail hatasını verdiriyor ve kendini kapatıyor : )







Bu kod ile npc pid lerini yüklüyor ..





Kod:
m_pHeader->ReadPid = _getpid();




Aşağıda AI Serverın yüklediği gibi hafızasına ITEM tablosunu yüklüyor.





Kod:
void CItemTableSet::DoFieldExchange(CFieldExchange* pFX) {     //{{AFX_FIELD_MAP(CItemTableSet)     pFX->SetFieldType(CFieldExchange::outputColumn);     RFX_Long(pFX, _T("[Num]"), m_Num);     RFX_Text(pFX, _T("[strName]"), m_strName);     RFX_Byte(pFX, _T("[Kind]"), m_Kind);     RFX_Byte(pFX, _T("[Slot]"), m_Slot);     RFX_Byte(pFX, _T("[Race]"), m_Race);     RFX_Byte(pFX, _T("[Class]"), m_Class);     RFX_Int(pFX, _T("[Damage]"), m_Damage);     RFX_Int(pFX, _T("[Delay]"), m_Delay);     RFX_Int(pFX, _T("[Range]"), m_Range);     RFX_Int(pFX, _T("[Weight]"), m_Weight);     RFX_Int(pFX, _T("[Duration]"), m_Duration);     RFX_Long(pFX, _T("[BuyPrice]"), m_BuyPrice);     RFX_Long(pFX, _T("[SellPrice]"), m_SellPrice);     RFX_Int(pFX, _T("[Ac]"), m_Ac);     RFX_Byte(pFX, _T("[Countable]"), m_Countable);     RFX_Long(pFX, _T("[Effect1]"), m_Effect1);     RFX_Long(pFX, _T("[Effect2]"), m_Effect2);     RFX_Byte(pFX, _T("[ReqLevel]"), m_ReqLevel);     RFX_Byte(pFX, _T("[ReqRank]"), m_ReqRank);     RFX_Byte(pFX, _T("[ReqTitle]"), m_ReqTitle);     RFX_Byte(pFX, _T("[ReqStr]"), m_ReqStr);     RFX_Byte(pFX, _T("[ReqSta]"), m_ReqSta);     RFX_Byte(pFX, _T("[ReqDex]"), m_ReqDex);     RFX_Byte(pFX, _T("[ReqIntel]"), m_ReqIntel);     RFX_Byte(pFX, _T("[ReqCha]"), m_ReqCha);     RFX_Byte(pFX, _T("[SellingGroup]"), m_SellingGroup);     RFX_Byte(pFX, _T("[ItemType]"), m_ItemType);     RFX_Int(pFX, _T("[Hitrate]"), m_Hitrate);     RFX_Int(pFX, _T("[Evasionrate]"), m_Evasionrate);     RFX_Int(pFX, _T("[DaggerAc]"), m_DaggerAc);     RFX_Int(pFX, _T("[SwordAc]"), m_SwordAc);     RFX_Int(pFX, _T("[MaceAc]"), m_MaceAc);     RFX_Int(pFX, _T("[AxeAc]"), m_AxeAc);     RFX_Int(pFX, _T("[SpearAc]"), m_SpearAc);     RFX_Int(pFX, _T("[BowAc]"), m_BowAc);     RFX_Byte(pFX, _T("[FireDamage]"), m_FireDamage);     RFX_Byte(pFX, _T("[IceDamage]"), m_IceDamage);     RFX_Byte(pFX, _T("[LightningDamage]"), m_LightningDamage);     RFX_Byte(pFX, _T("[PoisonDamage]"), m_PoisonDamage);     RFX_Byte(pFX, _T("[HPDrain]"), m_HPDrain);     RFX_Byte(pFX, _T("[MPDamage]"), m_MPDamage);     RFX_Byte(pFX, _T("[MPDrain]"), m_MPDrain);     RFX_Byte(pFX, _T("[MirrorDamage]"), m_MirrorDamage);     RFX_Byte(pFX, _T("[Droprate]"), m_Droprate);     RFX_Int(pFX, _T("[StrB]"), m_StrB);     RFX_Int(pFX, _T("[StaB]"), m_StaB);     RFX_Int(pFX, _T("[DexB]"), m_DexB);     RFX_Int(pFX, _T("[IntelB]"), m_IntelB);     RFX_Int(pFX, _T("[ChaB]"), m_ChaB);     RFX_Int(pFX, _T("[MaxHpB]"), m_MaxHpB);     RFX_Int(pFX, _T("[MaxMpB]"), m_MaxMpB);     RFX_Int(pFX, _T("[FireR]"), m_FireR);     RFX_Int(pFX, _T("[ColdR]"), m_ColdR);     RFX_Int(pFX, _T("[LightningR]"), m_LightningR);     RFX_Int(pFX, _T("[MagicR]"), m_MagicR);     RFX_Int(pFX, _T("[PoisonR]"), m_PoisonR);     RFX_Int(pFX, _T("[CurseR]"), m_CurseR);     //}}AFX_FIELD_MAP }




Hata mesajları için detaylı bilgileri açıklıyor ..





Kod:
void DisplayErrorMsg(SQLHANDLE hstmt) {     SQLCHAR       SqlState[6], Msg[1024];     SQLINTEGER    NativeError;     SQLSMALLINT   i, MsgLen;     SQLRETURN     rc2;     char          logstr[512];     memset( logstr, NULL, 512 );      i = 1;     while ((rc2 = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)     {         sprintf( logstr, "*** %s, %d, %s, %d ***\r\n", SqlState,NativeError,Msg,MsgLen );         LogFileWrite( logstr ); //        TRACE("*** %s, %d, %s, %d ***\n", SqlState,NativeError,Msg,MsgLen);          i++;     } }
SQLINTEGER = Sayı

SQLSMALLINT = Ufak Sayı

SQLCHAR = Bağlantı Durumu[6],Mesaj[1024]

SQLRETURN = Döndürülecek Değer

char = Kayıt[512]



SQL da tanımladığımız gibi değişken tanımlıyor ve byte değerlerini veriyor.1024 byte 1 kb tarzı ..



rc2 yi (dönen değeri) almak için SQLGetDiagRec fonksiyonu kullanılıyor.Bu yukarılarda bi yerlerde tanımlanmış ama bulamadım
biggrin.gif


Bu fonksiyon sonunda eğer alınan bir bilgi yoksa ( ' ! ' ifadesini anlatmıştım.Veri yoksa anlamına gelmekteydi ) SQL_NO_DATA verisi rc2 ye alınıyor ve ona göre işlem yapılıyor : )

Diğer bölümlerdede logstr yani tanımladığı Kayıt değişkenini log a yazdırıyor.







Kodda 10 sn içinde ebenezere bağlanılamazsa yapılacaklar anlatılıyor ..



Kod:
m_GameDB.SetLoginTimeout (10);     if( !m_GameDB.Open(NULL,FALSE,FALSE,strConnect) )     {         AfxMessageBox("GameDB SQL Connection Fail...");         return FALSE;     }




Aujard birçok db ye bağlanmaya çalışıyor.Bunlar sql da kayıtlı olan db ler değil,kendi hafızasında oluşturduğu paylaşılan veritabanları.Bunlar için yeride sizin verdiğiniz bilgilerdeki sql a bağlanarak yapıyor ama siz oluşturduğunu görmüyorsunuz : )







Bu döngüde ınventoryniz hakkında bilgiler alınıyor.Bunlar db den değil,hafızadan alınıyor.





Kod:
for(i = 0; i < SLOT_MAX+HAVE_MAX; i++) {// Âø¿ë°¹¼ö + ¼ÒÀ¯°¹¼ö(14+28=42)         pUser->m_sItemArray[i].nNum = 0;         pUser->m_sItemArray[i].sDuration = 0;         pUser->m_sItemArray[i].sCount = 0;     }


14 + 28 = 42 işlemini sanırım inventorydeki slot sayısı için koymuş.Sadece açıklama amaçlı oyuna bir etkisi yok.Düzeltilerek oyuna fazla inventory eklenemez : )

Iteminizin kalan dayanıklılığı,sayısı ve item kodu yükleniyor ..





Burada gene değişkenler tanımlanıyor ..



SQLCHAR Nation, Race, HairColor, Rank, Title, Level;

SQLINTEGER Exp, Loyalty, Gold, PX, PZ, PY, dwTime;

SQLCHAR Face, City, Fame, Authority, Points;

SQLSMALLINT Hp, Mp, Sp, sRet, Class, Bind, Knights;

SQLCHAR Str, Sta, Dex, Intel, Cha, Zone;



Bu işlem karakter yüklenmeye başlanırken yapılıyor.Bunun yanında bizim decode etmeden okuyamayacağımız :



TCHAR strSkill[10], strItem[400], strSerial[400];

memset( strSkill, 0x00, 10 );

memset( strItem, 0x00, 400 );

memset( strSerial, 0x00, 400 );



Skill , Item ve Serial bilgileride alınıyor.



memset = Memory Set ( Hafıza Ayarlama )



Yani bilgileri gene hafızasına alıyor : )







Aujard DBProcessNumber ile veritabanının işlendiği zamanı bölüyor.Yani DBProcessumber(1) işleminde item bilgisi yükleniyordu.Eğer orada bir hata olursa item yüklenemedi hatası veriyor.DBProcessNumber(1) deki işlemleri bitince

DBProcessNumber(2) ye geçiyor ve karakter bilgilerini yüklemeye başlıyor.Hata ve log için yapıldığını zannediyorum : )







SQL Varlığı kontrol ediliyor ..





Kod:
retcode = SQLAllocHandle( (SQLSMALLINT)SQL_HANDLE_STMT, m_GameDB.m_hdbc, &hstmt );     if (retcode != SQL_SUCCESS)    {         memset( logstr, 0x00, 256);         sprintf( logstr, "LoadUserData Fail 000 : name=%s\r\n", userid );     //    m_pMain->m_LogFile.Write(logstr, strlen(logstr));         return FALSE;      }
retcode = Return Code ( Geri Döndüğünde Alınacak Veri )



Eğer retcode boş ise karakteri yükleyemiyor ve hata veriyor.Bunu mesaj oalrak değil,loga yazıyor tabiki : ) Buradaki != ifadesi eşit değil anlamında kullanılmış ..





Aujard strSerial kısmında itemlerin serial numarasını kontrol eder.Bizde dupeleri bu sistemi çözerek %100 kapatabiliriz : )







Aujard class a göre başlangıç itemi veriyor : ) Benim açıkladığım sourcelar 1098 olduğu için 1098 tablolarını inceledim.Ve 180050000 item numarasına karşılık gelen item ITEM_BASIC tablosunda Wooden Staff olarak gözüküyor : ) İşte bir örnek :





Kod:
180050000    22    Wooden Staff                                                                                  Basic Magician Item                                                                                                                                            18021000    18021000    330    341    110    0    3    0    0    40    200    10    30    5000    50    1    0    0    0    0    1    0    0    0    0    0    0    0    0
Her class a göre veriliyor .. Tabi 1098 db lerde race ve class numarası farklı.1299 larda 100 ve 200 küsürlerle başlıyor, 1098 lerde 1 den bile başlayabiliyor ..







Aşağıda karakterde bir değişiklik olduğunda ai serverdan alınan bilgi ile UPDATE_USER_DATA prosedürü çalıştırılıyor ve bilgiler ekleniyor.





Kod:
wsprintf( szSQL, TEXT( "{call UPDATE_USER_DATA ( \'%s\', %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,?,?,?)}" ),         pUser->m_id, pUser->m_bNation, pUser->m_bRace, pUser->m_sClass, pUser->m_bHairColor, pUser->m_bRank,         pUser->m_bTitle, pUser->m_bLevel, pUser->m_iExp, pUser->m_iLoyalty, pUser->m_bFace,          pUser->m_bCity,    pUser->m_bKnights, pUser->m_bFame, pUser->m_sHp, pUser->m_sMp, pUser->m_sSp,          pUser->m_bStr, pUser->m_bSta, pUser->m_bDex, pUser->m_bIntel, pUser->m_bCha, pUser->m_bAuthority, pUser->m_bPoints, pUser->m_iGold, pUser->m_bZone, pUser->m_sBind,          (int)(pUser->m_curx*100), (int)(pUser->m_curz*100), (int)(pUser->m_cury*100), pUser->m_dwTime );
Biz oyundayken aynı bu şekilde yaptığımızda kaydedildi gözüküyor ama oyunda karaktere işlemiyor.Ama aujard yapınca tak diye işliyor .. Olacak iş değil : )







Oyun veritabanı varsa binary değerlere (strSkill,strItem,strSerial) birşeyler yapılıyor ama çözemedim : )





Kod:
retcode = SQLAllocHandle( (SQLSMALLINT)SQL_HANDLE_STMT, m_GameDB.m_hdbc, &hstmt );     if (retcode == SQL_SUCCESS)     {         retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(strSkill),0, strSkill,0, &sStrSkill );         retcode = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(strItem),0, strItem,0, &sStrItem );         retcode = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(strSerial),0, strSerial,0, &sStrSerial );




Aujard login isteklerini kontrol eder.





Kod:
int CDBAgent::AccountLogInReq( char *id, char *pw ) {     SQLHSTMT        hstmt = NULL;     SQLRETURN        retcode;     TCHAR            szSQL[1024];     memset( szSQL, 0x00, 1024 );     SQLSMALLINT        sParmRet;     SQLINTEGER        cbParmRet=SQL_NTS;  wsprintf( szSQL, TEXT( "{call ACCOUNT_LOGIN( \'%s\', \'%s\', ?)}" ), id, pw);
AccountLogInReq = HesapGirişIstegi ( Req = Request = Istek )



Bu doğrultuda değişkenlerde tanımlanmış oluyor.Gelen istek doğrultusunda ACCOUNT_LOGIN prosedürüne bilgiler gönderiliyor ve account_login de yazanlar uygulanıyor ..







Aşağıda ırk seçimi belirleniyor ..





Kod:
BOOL CDBAgent::NationSelect(char *id, int nation) {     SQLHSTMT        hstmt = NULL;     SQLRETURN        retcode;     TCHAR            szSQL[1024];     memset( szSQL, 0x00, 1024 );     SQLSMALLINT        sParmRet;     SQLINTEGER        cbParmRet=SQL_NTS;      wsprintf( szSQL, TEXT( "{call NATION_SELECT ( ?, \'%s\', %d)}" ), id, nation);
Yine değişkenler tanımlanıp NATION_SELECT prosedürüne bilgiler gönderiliyor .. Bunu 1098 de SiliconShadow fixlemişti : )







Yeni karakter açılmak istendiğinde client aujard a istek gönderiyor ..





Kod:
int CDBAgent::CreateNewChar(char *accountid, int index, char *charid, int race, int Class, int hair, int face, int str, int sta, int dex, int intel, int cha) {     SQLHSTMT        hstmt = NULL;     SQLRETURN        retcode;     TCHAR            szSQL[1024];     memset( szSQL, 0x00, 1024 );     SQLSMALLINT        sParmRet;     SQLINTEGER        cbParmRet=SQL_NTS;      wsprintf( szSQL, TEXT( "{call CREATE_NEW_CHAR ( ?, \'%s\', %d, \'%s\', %d,%d,%d,%d,%d,%d,%d,%d,%d)}" ), accountid, index, charid, race, Class, hair, face, str, sta, dex, intel, cha );
Aujard da CREATE_NEW_CHAR prosedürünü çalıştırıp gerekenleri yapıyor saolsun : )







Bakın şimdi buraya dikkat .. 1098 sourcelarında karakter silme aktif,1299 sourcelarındada aktif.Yani hex ler bize açık olduğunu söylüyor çünkü DELETE_CHAR prosedürü çalıştırılıyor.

Tek sorun client in karakter silmek istendiğinde istek yerine hata mesajı göndermesi : )





Kod:
BOOL CDBAgent::DeleteChar(int index, char *id, char *charid, char* socno) {     SQLHSTMT        hstmt = NULL;     SQLRETURN        retcode;     TCHAR            szSQL[1024];     memset( szSQL, 0x00, 1024 );     SQLSMALLINT        sParmRet;     SQLINTEGER        cbParmRet=SQL_NTS;      wsprintf( szSQL, TEXT( "{ call DELETE_CHAR ( \'%s\', %d, \'%s\', \'%s\', ? )}" ), id, index, charid, socno );
DELETE_CHAR prosedürü çalıştırılıp gerekenler yapılıyor ...







Birde buraya dikkat : ) 1098 db lerde CHECK_COUPON_EVENT diye bir prosedür bulunmuyor.Ama 1098 aujard bunu okuyor.Yani buda sadece 1299 ların değil,1098 db lerinde eksik olduğunu gösteriyor : )





Kod:
BOOL CDBAgent::CheckCouponEvent( const char* accountid ) {     SQLHSTMT        hstmt = NULL;     SQLRETURN        retcode;     BOOL            bData = TRUE,    retval = FALSE;     TCHAR            szSQL[1024];     memset( szSQL, 0x00, 1024 );      SQLINTEGER Indexind = SQL_NTS;     SQLSMALLINT sRet = 0;      wsprintf(szSQL, TEXT("{call CHECK_COUPON_EVENT (\'%s\', ?)}"), accountid);
Sadece hesap adı gönderiliyor.Ne amaçla gönderilmiş belli değil ..





Sanırım yukarıda o hesabın eventa katılıp,katılmadığı kontrol ediliyor.Aşağıda ise event güncelleştiriliyor ..





Kod:
BOOL CDBAgent::UpdateCouponEvent( const char* accountid, char* charid, char* cpid, int itemid, int count ) {     SQLHSTMT        hstmt = NULL;     SQLRETURN        retcode;     BOOL            bData = TRUE,    retval = FALSE;     TCHAR            szSQL[1024];     memset( szSQL, 0x00, 1024 );      SQLINTEGER Indexind = SQL_NTS;     SQLSMALLINT sRet = 0;      wsprintf(szSQL, TEXT("{call UPDATE_COUPON_EVENT (\'%s\', \'%s\', \'%s\', %d, %d)}"), accountid, charid, cpid, itemid, count);
Hesap Adı,Karakter Adı,Pid(Görünüş),Item Kodu ve Sayısı güncelleştiriliyor veya ekleniyor.Bunu sadece prosedürden anlayabiliriz ..







: Aujard ın yaptığı bazı işlemleri gösteren bir kod :

Kod:
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;

            }




Hesabı oyuna sokar,

Karakter açar,

Karakter siler,

Karakter seçer,

Irk seçer,

Karakter bilgilerini yollar,

Hesabı düşürür,

Oyuncuyu kaydeder,

Clanları kontrol eder,( Salak 2 kere etmiş
biggrin.gif
)

User kickler,

Event yönetir ..







Aşağıda zaman aralıklarıyla yaptığı işleri siliyor ..





Kod:
KillTimer( PROCESS_CHECK );     KillTimer( CONCURRENT_CHECK );     KillTimer( SERIAL_TIME );     KillTimer( PACKET_CHECK );


Shared Memory Open Fail hatasını mapları okuyamadığı için vermişti.Burada da yükleyemediği için hata vermesini sağlıyor ..





Kod:
m_hMMFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, TRUE, "KNIGHT_DB" );     if( m_hMMFile == NULL ) {         logstr = "Shared Memory Load Fail!!";         m_hMMFile = INVALID_HANDLE_VALUE;          return FALSE;     }
hMMFile değişkenine OpenFileMapping den gelen değer yazdırılıyor.Bu büyük ihtimal eğer harita dosyası yüklenmişse 1 , yüklenmemişse boş gönderiyor.

Eğer bu hMMFile değişkeni boş ise Shared Memory Load Fail hatası verdiriliyor ..





Burada zaman aralıklı yapacağı işlerin süreleri belirleniyor.Saniye olarak değil,milisaniye olarak ölçülüyor.Yani 1000 ile çarpılarak : ) 4000 = 4 Saniye ise 400 = 0.4 saniye yani ...



Kod:

#define PROCESS_CHECK 100 #define CONCURRENT_CHECK 200 #define SERIAL_TIME 300 #define PACKET_CHECK 400





Burada bir dosya boyutunu userdatadaki oyuncu sayısını 4000 ile çarpıp belirliyor





Kod:
      DWORD filesize = MAX_USER * 4000;
Tabi çıkan sayı megabyte değil,byte cinsinden ölçülüyor .. Hangi dosyaya yapıyor bulamadım ^^







AI Serverda yaptığı gibi tablonun varlığı ve açılıp,açılmaması kontrol ediliyor ..






Kod:
if( !ItemTableSet.Open() ) {         AfxMessageBox(_T("ItemTable Open Fail!"));         return FALSE;     }     if(ItemTableSet.IsBOF() || ItemTableSet.IsEOF()) {         AfxMessageBox(_T("ItemTable Empty!"));         return FALSE;     }
Başlangıcı ile Sonu arasında veri yoksa ( IsEOF l l IsBOF ) boş,açılışta veri alınamazsa ( gene ! işareti ) Açılamadı hatası veriliyor ..







Burada ise hafizasına itemleri yüklüyor.AI Serverda olduğu gibi ..





Kod:
while( !ItemTableSet.IsEOF() )     {         _ITEM_TABLE* pTableItem = new _ITEM_TABLE;
Tablo sonuna kadar bilgileri yüklüyor.Biraz uzun olduğu için onlar kopyalamadım : )







Clanlara ait bilgileri yüklüyor,ırkına göre ..





Kod:
      m_DBAgent.LoadKnightsAllList( nation );




Coupon Event olayına kafamı taktım : ) Buradada birkaç bilgi var belki incelersiniz .





Kod:
void CAujardDlg::CouponEvent( char* pData ) {     int nSid = 0, nEventNum = 0, nLen = 0, nCharLen=0, nCouponLen=0, index = 0, nType = 0, nResult = 0, send_index = 0, count = 0;     int nItemID = 0, nItemCount = 0, nMessageNum = 0;     char strAccountName[MAX_ID_SIZE+1];    memset( strAccountName, 0x00, MAX_ID_SIZE+1 );     char strCharName[MAX_ID_SIZE+1];    memset( strCharName, 0x00, MAX_ID_SIZE+1 );     char strCouponID[MAX_ID_SIZE+1];    memset( strCouponID, 0x00, MAX_ID_SIZE+1 );     char send_buff[256]; memset( send_buff, 0x00, 256 );
Ne yapıldığını anlayamadım







İşte buradanda COUPON_EVENT tablosunun sekme isimlerini alıyoruz : )





Kod:
nResult = m_DBAgent.UpdateCouponEvent( strAccountName, strCharName, strCouponID, nItemID, nIte


AlıntıHiFi


 
Coupon_Event dediği PPCARD yani Pre-Paid Card'dır. Bu oyun ilk başta WOW gibi Pre-Paid Card sistemi üzerine kuruldu. Yani oyunu oynamak için aylık olarak ücret ödeyip pre-paid card satın almanız gerekecekti. Tabii, oyun piyasaya çıktığında bu sistem kullanılmadı. Bu sistemi kullananlar var elbet, SOHU KO 2.0 Linux dosyalarında bu sistemi çalıştırmış ve kullanmıştı.
 
Geri
Üst