TrayhopeR
www.trayhoper.net
- May
- 2,830
- 62
Ebenezer ve AI Server ın işlevlerini açıkladıktan sonra sıra geldi aujarda : ) Bakalım bu aujard baba neler yapıyor ?_? 
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.
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 ..
--------------------------------------
Aşağıda AI Serverın yüklediği gibi hafızasına ITEM tablosunu yüklüyor.
------------------------------------------
Hata mesajları için detaylı bilgileri açıklıyor ..
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
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 ..
-----------------------------------------------
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.
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 ..
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 :
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.
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 : )
---------------------------------------------------
Aujard login isteklerini kontrol eder.
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 ..
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 ..
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 : )
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 : )
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 ..
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 :
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ş
)
User kickler,
Event yönetir ..
-----------------------------------------------------
Aşağıda zaman aralıklarıyla yaptığı işleri siliyor ..
-----------------------------------------------------
Shared Memory Open Fail hatasını mapları okuyamadığı için vermişti.Burada da yükleyemediği için hata vermesini sağlıyor ..
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 ...
-----------------------------------------------------
Burada bir dosya boyutunu userdatadaki oyuncu sayısını 4000 ile çarpıp belirliyor.
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 ..
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 ..
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 ..
----------------------------------------------------
Coupon Event olayına kafamı taktım : ) Buradada birkaç bilgi var belki incelersiniz ..
Ne yapıldığını anlayamadım ^^
----------------------------------------------------
İşte buradanda COUPON_EVENT tablosunun sekme isimlerini alıyoruz : )
Bu kupon eventı nedir ne işdir hiç anlamış değilim.Bizim db lerde olmadığı için 1098 de kullanamamıştık.Ama uskodada ben böyle bir kuponlu birşey hatırlamıyorum.
Yani 1098 de varsa,1453 dede olmalıydı.Hadi onuda geçtim 1098 dede olmalıydı ve böyle birşey hatırlamıyorum .. : )
---------------------------------------------------
Kısacası aujard prosedürlerden aldığı bilgilerle veritabanını şekillendiren güzel bir program ^^ Kafanızda soru işaretlerini bu konudan sorabilirsiniz .. Ayrıca unutmayın login server hariç bütün server dosyaları birbiriyle bağlantı kurar.Birini açıp,birini açmama olayında gösterilmeyen hata mesajları,onunla bağlantı yapmadığı anlamına gelmez.Kodlardaki sIndex ve pData değişkenleri hep diğer server dosyalarından geliyor
Haydi Sağlıcakla ..
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
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;
}
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;
}
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
-------------------------------------------------
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);
----------------------------------------------------
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 :
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ş
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;
}
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;
}
-----------------------------------------------------
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 );
----------------------------------------------------
İşte buradanda COUPON_EVENT tablosunun sekme isimlerini alıyoruz : )
Kod:
nResult = m_DBAgent.UpdateCouponEvent( strAccountName, strCharName, strCouponID, nItemID, nItemCount);
Bu kupon eventı nedir ne işdir hiç anlamış değilim.Bizim db lerde olmadığı için 1098 de kullanamamıştık.Ama uskodada ben böyle bir kuponlu birşey hatırlamıyorum.
Yani 1098 de varsa,1453 dede olmalıydı.Hadi onuda geçtim 1098 dede olmalıydı ve böyle birşey hatırlamıyorum .. : )
---------------------------------------------------
Kısacası aujard prosedürlerden aldığı bilgilerle veritabanını şekillendiren güzel bir program ^^ Kafanızda soru işaretlerini bu konudan sorabilirsiniz .. Ayrıca unutmayın login server hariç bütün server dosyaları birbiriyle bağlantı kurar.Birini açıp,birini açmama olayında gösterilmeyen hata mesajları,onunla bağlantı yapmadığı anlamına gelmez.Kodlardaki sIndex ve pData değişkenleri hep diğer server dosyalarından geliyor
Haydi Sağlıcakla ..
2.000.000 TL ⚔️ Ödüllü MYKOv2 GENESIS | 24 Nisan 2026 ⚔️ Resmi Açılış Başlıyor!